Merge "Fwk matrix use PLATFORM_SEPOLICY_*" am: 8f7ff5730b am: 9dda065989
am: 777d18ccaf

Change-Id: I076b6a910f6b6c43b00beb42cdf19502514f2e9f
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 3788bc6..00d0aa5 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -60,6 +60,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/hw/android.hardware.automotive*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/hw/android.hardware.automotive*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/android.hardware.automotive*)
-$(call add-clean-step, find $(PRODUCT_OUT)/system $(PRODUCT_OUT)/vendor -type f -name "android\.hardware\.configstore\@1\.1*" -print0 | xargs -0 rm -f)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/android.hardware.tests*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk/android.hardware.tests*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/vndk-sp/android.hardware.graphics.allocator*)
+$(call add-clean-step, find $(PRODUCT_OUT)/system $(PRODUCT_OUT)/vendor -type f -name "android\.hardware\.configstore\@1\.1*" -print0 | xargs -0 rm -f)
diff --git a/audio/2.0/default/Android.mk b/audio/2.0/default/Android.mk
index aa25077..12713d3 100644
--- a/audio/2.0/default/Android.mk
+++ b/audio/2.0/default/Android.mk
@@ -16,45 +16,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.audio@2.0-impl
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_SRC_FILES := \
-    Conversions.cpp \
-    Device.cpp \
-    DevicesFactory.cpp \
-    ParametersUtil.cpp \
-    PrimaryDevice.cpp \
-    Stream.cpp \
-    StreamIn.cpp \
-    StreamOut.cpp \
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libfmq \
-    libhardware \
-    libhidlbase \
-    libhidltransport \
-    liblog \
-    libutils \
-    android.hardware.audio@2.0 \
-    android.hardware.audio.common@2.0 \
-    android.hardware.audio.common@2.0-util \
-
-LOCAL_HEADER_LIBRARIES := \
-    libaudioclient_headers \
-    libaudio_system_headers \
-    libhardware_headers \
-    libmedia_headers \
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libmedia_helper
-
-include $(BUILD_SHARED_LIBRARY)
-
 #
 # Service
 #
@@ -79,9 +40,10 @@
     android.hardware.audio.common@2.0 \
     android.hardware.audio.effect@2.0 \
     android.hardware.soundtrigger@2.0 \
-    android.hardware.broadcastradio@1.0 \
-    android.hardware.broadcastradio@1.1
+    android.hardware.soundtrigger@2.1
 
+# Can not switch to Android.bp until AUDIOSERVER_MULTILIB
+# is deprecated as build config variable are not supported
 ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
 LOCAL_MULTILIB := 32
 else
diff --git a/audio/2.0/default/Conversions.cpp b/audio/2.0/default/Conversions.cpp
deleted file mode 100644
index e669185..0000000
--- a/audio/2.0/default/Conversions.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.
- */
-
-#include <stdio.h>
-
-#include "Conversions.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-std::string deviceAddressToHal(const DeviceAddress& address) {
-    // HAL assumes that the address is NUL-terminated.
-    char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
-    memset(halAddress, 0, sizeof(halAddress));
-    uint32_t halDevice = static_cast<uint32_t>(address.device);
-    const bool isInput = (halDevice & AUDIO_DEVICE_BIT_IN) != 0;
-    if (isInput) halDevice &= ~AUDIO_DEVICE_BIT_IN;
-    if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0)
-            || (isInput && (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
-        snprintf(halAddress, sizeof(halAddress),
-                "%02X:%02X:%02X:%02X:%02X:%02X",
-                address.address.mac[0], address.address.mac[1], address.address.mac[2],
-                address.address.mac[3], address.address.mac[4], address.address.mac[5]);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_IP) != 0)
-            || (isInput && (halDevice & AUDIO_DEVICE_IN_IP) != 0)) {
-        snprintf(halAddress, sizeof(halAddress),
-                "%d.%d.%d.%d",
-                address.address.ipv4[0], address.address.ipv4[1],
-                address.address.ipv4[2], address.address.ipv4[3]);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0)
-            || (isInput && (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0)) {
-        snprintf(halAddress, sizeof(halAddress),
-                "card=%d;device=%d",
-                address.address.alsa.card, address.address.alsa.device);
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_BUS) != 0)
-            || (isInput && (halDevice & AUDIO_DEVICE_IN_BUS) != 0)) {
-        snprintf(halAddress, sizeof(halAddress),
-                "%s", address.busAddress.c_str());
-    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0
-            || (isInput && (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
-        snprintf(halAddress, sizeof(halAddress),
-                "%s", address.rSubmixAddress.c_str());
-    }
-    return halAddress;
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
diff --git a/audio/2.0/default/Conversions.h b/audio/2.0/default/Conversions.h
deleted file mode 100644
index ebda5c5..0000000
--- a/audio/2.0/default/Conversions.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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_audio_V2_0_Conversions_H_
-#define android_hardware_audio_V2_0_Conversions_H_
-
-#include <string>
-
-#include <android/hardware/audio/2.0/types.h>
-#include <system/audio.h>
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::V2_0::DeviceAddress;
-
-std::string deviceAddressToHal(const DeviceAddress& address);
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // android_hardware_audio_V2_0_Conversions_H_
diff --git a/audio/2.0/default/Device.cpp b/audio/2.0/default/Device.cpp
deleted file mode 100644
index 3727966..0000000
--- a/audio/2.0/default/Device.cpp
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
-* 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 "DeviceHAL"
-//#define LOG_NDEBUG 0
-
-#include <algorithm>
-#include <memory.h>
-#include <string.h>
-
-#include <android/log.h>
-
-#include "Conversions.h"
-#include "Device.h"
-#include "HidlUtils.h"
-#include "StreamIn.h"
-#include "StreamOut.h"
-#include "Util.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-Device::Device(audio_hw_device_t* device)
-        : mDevice(device) {
-}
-
-Device::~Device() {
-    int status = audio_hw_device_close(mDevice);
-    ALOGW_IF(status, "Error closing audio hw device %p: %s", mDevice,
-             strerror(-status));
-    mDevice = nullptr;
-}
-
-Result Device::analyzeStatus(const char* funcName, int status) {
-    if (status != 0) {
-        ALOGW("Device %p %s: %s", mDevice, funcName, strerror(-status));
-    }
-    switch (status) {
-        case 0:
-            return Result::OK;
-        case -EINVAL:
-            return Result::INVALID_ARGUMENTS;
-        case -ENODATA:
-            return Result::INVALID_STATE;
-        case -ENODEV:
-            return Result::NOT_INITIALIZED;
-        case -ENOSYS:
-            return Result::NOT_SUPPORTED;
-        default:
-            return Result::INVALID_STATE;
-    }
-}
-
-void Device::closeInputStream(audio_stream_in_t* stream) {
-    mDevice->close_input_stream(mDevice, stream);
-}
-
-void Device::closeOutputStream(audio_stream_out_t* stream) {
-    mDevice->close_output_stream(mDevice, stream);
-}
-
-char* Device::halGetParameters(const char* keys) {
-    return mDevice->get_parameters(mDevice, keys);
-}
-
-int Device::halSetParameters(const char* keysAndValues) {
-    return mDevice->set_parameters(mDevice, keysAndValues);
-}
-
-// Methods from ::android::hardware::audio::V2_0::IDevice follow.
-Return<Result> Device::initCheck() {
-    return analyzeStatus("init_check", mDevice->init_check(mDevice));
-}
-
-Return<Result> Device::setMasterVolume(float volume) {
-    if (mDevice->set_master_volume == NULL) {
-        return Result::NOT_SUPPORTED;
-    }
-    if (!isGainNormalized(volume)) {
-        ALOGW("Can not set a master volume (%f) outside [0,1]", volume);
-        return Result::INVALID_ARGUMENTS;
-    }
-    return analyzeStatus("set_master_volume",
-                         mDevice->set_master_volume(mDevice, volume));
-}
-
-Return<void> Device::getMasterVolume(getMasterVolume_cb _hidl_cb) {
-    Result retval(Result::NOT_SUPPORTED);
-    float volume = 0;
-    if (mDevice->get_master_volume != NULL) {
-        retval = analyzeStatus("get_master_volume",
-                               mDevice->get_master_volume(mDevice, &volume));
-    }
-    _hidl_cb(retval, volume);
-    return Void();
-}
-
-Return<Result> Device::setMicMute(bool mute) {
-    return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute));
-}
-
-Return<void> Device::getMicMute(getMicMute_cb _hidl_cb) {
-    bool mute = false;
-    Result retval =
-        analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute));
-    _hidl_cb(retval, mute);
-    return Void();
-}
-
-Return<Result> Device::setMasterMute(bool mute) {
-    Result retval(Result::NOT_SUPPORTED);
-    if (mDevice->set_master_mute != NULL) {
-        retval = analyzeStatus("set_master_mute",
-                               mDevice->set_master_mute(mDevice, mute));
-    }
-    return retval;
-}
-
-Return<void> Device::getMasterMute(getMasterMute_cb _hidl_cb) {
-    Result retval(Result::NOT_SUPPORTED);
-    bool mute = false;
-    if (mDevice->get_master_mute != NULL) {
-        retval = analyzeStatus("get_master_mute",
-                               mDevice->get_master_mute(mDevice, &mute));
-    }
-    _hidl_cb(retval, mute);
-    return Void();
-}
-
-Return<void> Device::getInputBufferSize(const AudioConfig& config,
-                                        getInputBufferSize_cb _hidl_cb) {
-    audio_config_t halConfig;
-    HidlUtils::audioConfigToHal(config, &halConfig);
-    size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig);
-    Result retval(Result::INVALID_ARGUMENTS);
-    uint64_t bufferSize = 0;
-    if (halBufferSize != 0) {
-        retval = Result::OK;
-        bufferSize = halBufferSize;
-    }
-    _hidl_cb(retval, bufferSize);
-    return Void();
-}
-
-Return<void> Device::openOutputStream(int32_t ioHandle,
-                                      const DeviceAddress& device,
-                                      const AudioConfig& config,
-                                      AudioOutputFlag flags,
-                                      openOutputStream_cb _hidl_cb) {
-    audio_config_t halConfig;
-    HidlUtils::audioConfigToHal(config, &halConfig);
-    audio_stream_out_t* halStream;
-    ALOGV(
-        "open_output_stream handle: %d devices: %x flags: %#x "
-        "srate: %d format %#x channels %x address %s",
-        ioHandle, static_cast<audio_devices_t>(device.device),
-        static_cast<audio_output_flags_t>(flags), halConfig.sample_rate,
-        halConfig.format, halConfig.channel_mask,
-        deviceAddressToHal(device).c_str());
-    int status = mDevice->open_output_stream(
-        mDevice, ioHandle, static_cast<audio_devices_t>(device.device),
-        static_cast<audio_output_flags_t>(flags), &halConfig, &halStream,
-        deviceAddressToHal(device).c_str());
-    ALOGV("open_output_stream status %d stream %p", status, halStream);
-    sp<IStreamOut> streamOut;
-    if (status == OK) {
-        streamOut = new StreamOut(this, halStream);
-    }
-    AudioConfig suggestedConfig;
-    HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig);
-    _hidl_cb(analyzeStatus("open_output_stream", status), streamOut,
-             suggestedConfig);
-    return Void();
-}
-
-Return<void> Device::openInputStream(int32_t ioHandle,
-                                     const DeviceAddress& device,
-                                     const AudioConfig& config,
-                                     AudioInputFlag flags, AudioSource source,
-                                     openInputStream_cb _hidl_cb) {
-    audio_config_t halConfig;
-    HidlUtils::audioConfigToHal(config, &halConfig);
-    audio_stream_in_t* halStream;
-    ALOGV(
-        "open_input_stream handle: %d devices: %x flags: %#x "
-        "srate: %d format %#x channels %x address %s source %d",
-        ioHandle, static_cast<audio_devices_t>(device.device),
-        static_cast<audio_input_flags_t>(flags), halConfig.sample_rate,
-        halConfig.format, halConfig.channel_mask,
-        deviceAddressToHal(device).c_str(),
-        static_cast<audio_source_t>(source));
-    int status = mDevice->open_input_stream(
-        mDevice, ioHandle, static_cast<audio_devices_t>(device.device),
-        &halConfig, &halStream, static_cast<audio_input_flags_t>(flags),
-        deviceAddressToHal(device).c_str(),
-        static_cast<audio_source_t>(source));
-    ALOGV("open_input_stream status %d stream %p", status, halStream);
-    sp<IStreamIn> streamIn;
-    if (status == OK) {
-        streamIn = new StreamIn(this, halStream);
-    }
-    AudioConfig suggestedConfig;
-    HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig);
-    _hidl_cb(analyzeStatus("open_input_stream", status), streamIn,
-             suggestedConfig);
-    return Void();
-}
-
-Return<bool> Device::supportsAudioPatches() {
-    return version() >= AUDIO_DEVICE_API_VERSION_3_0;
-}
-
-Return<void> Device::createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
-                                      const hidl_vec<AudioPortConfig>& sinks,
-                                      createAudioPatch_cb _hidl_cb) {
-    Result retval(Result::NOT_SUPPORTED);
-    AudioPatchHandle patch = 0;
-    if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
-        std::unique_ptr<audio_port_config[]> halSources(
-            HidlUtils::audioPortConfigsToHal(sources));
-        std::unique_ptr<audio_port_config[]> halSinks(
-            HidlUtils::audioPortConfigsToHal(sinks));
-        audio_patch_handle_t halPatch = AUDIO_PATCH_HANDLE_NONE;
-        retval = analyzeStatus(
-            "create_audio_patch",
-            mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0],
-                                        sinks.size(), &halSinks[0], &halPatch));
-        if (retval == Result::OK) {
-            patch = static_cast<AudioPatchHandle>(halPatch);
-        }
-    }
-    _hidl_cb(retval, patch);
-    return Void();
-}
-
-Return<Result> Device::releaseAudioPatch(int32_t patch) {
-    if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
-        return analyzeStatus(
-            "release_audio_patch",
-            mDevice->release_audio_patch(
-                mDevice, static_cast<audio_patch_handle_t>(patch)));
-    }
-    return Result::NOT_SUPPORTED;
-}
-
-Return<void> Device::getAudioPort(const AudioPort& port,
-                                  getAudioPort_cb _hidl_cb) {
-    audio_port halPort;
-    HidlUtils::audioPortToHal(port, &halPort);
-    Result retval = analyzeStatus("get_audio_port",
-                                  mDevice->get_audio_port(mDevice, &halPort));
-    AudioPort resultPort = port;
-    if (retval == Result::OK) {
-        HidlUtils::audioPortFromHal(halPort, &resultPort);
-    }
-    _hidl_cb(retval, resultPort);
-    return Void();
-}
-
-Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) {
-    if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
-        struct audio_port_config halPortConfig;
-        HidlUtils::audioPortConfigToHal(config, &halPortConfig);
-        return analyzeStatus(
-            "set_audio_port_config",
-            mDevice->set_audio_port_config(mDevice, &halPortConfig));
-    }
-    return Result::NOT_SUPPORTED;
-}
-
-Return<AudioHwSync> Device::getHwAvSync() {
-    int halHwAvSync;
-    Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync);
-    return retval == Result::OK ? halHwAvSync : AUDIO_HW_SYNC_INVALID;
-}
-
-Return<Result> Device::setScreenState(bool turnedOn) {
-    return setParam(AudioParameter::keyScreenState, turnedOn);
-}
-
-Return<void> Device::getParameters(const hidl_vec<hidl_string>& keys,
-                                   getParameters_cb _hidl_cb) {
-    getParametersImpl(keys, _hidl_cb);
-    return Void();
-}
-
-Return<Result> Device::setParameters(
-    const hidl_vec<ParameterValue>& parameters) {
-    return setParametersImpl(parameters);
-}
-
-Return<void> Device::debugDump(const hidl_handle& fd) {
-    if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
-        analyzeStatus("dump", mDevice->dump(mDevice, fd->data[0]));
-    }
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
diff --git a/audio/2.0/default/Device.h b/audio/2.0/default/Device.h
deleted file mode 100644
index 7738361..0000000
--- a/audio/2.0/default/Device.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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_AUDIO_V2_0_DEVICE_H
-#define ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H
-
-#include <memory>
-
-#include <media/AudioParameter.h>
-#include <hardware/audio.h>
-
-#include <android/hardware/audio/2.0/IDevice.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
-
-#include "ParametersUtil.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioConfig;
-using ::android::hardware::audio::common::V2_0::AudioHwSync;
-using ::android::hardware::audio::common::V2_0::AudioInputFlag;
-using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
-using ::android::hardware::audio::common::V2_0::AudioPatchHandle;
-using ::android::hardware::audio::common::V2_0::AudioPort;
-using ::android::hardware::audio::common::V2_0::AudioPortConfig;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::V2_0::DeviceAddress;
-using ::android::hardware::audio::V2_0::IDevice;
-using ::android::hardware::audio::V2_0::IStreamIn;
-using ::android::hardware::audio::V2_0::IStreamOut;
-using ::android::hardware::audio::V2_0::ParameterValue;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct Device : public IDevice, public ParametersUtil {
-    explicit Device(audio_hw_device_t* device);
-
-    // Methods from ::android::hardware::audio::V2_0::IDevice follow.
-    Return<Result> initCheck()  override;
-    Return<Result> setMasterVolume(float volume)  override;
-    Return<void> getMasterVolume(getMasterVolume_cb _hidl_cb)  override;
-    Return<Result> setMicMute(bool mute)  override;
-    Return<void> getMicMute(getMicMute_cb _hidl_cb)  override;
-    Return<Result> setMasterMute(bool mute)  override;
-    Return<void> getMasterMute(getMasterMute_cb _hidl_cb)  override;
-    Return<void> getInputBufferSize(
-            const AudioConfig& config, getInputBufferSize_cb _hidl_cb)  override;
-    Return<void> openOutputStream(
-            int32_t ioHandle,
-            const DeviceAddress& device,
-            const AudioConfig& config,
-            AudioOutputFlag flags,
-            openOutputStream_cb _hidl_cb)  override;
-    Return<void> openInputStream(
-            int32_t ioHandle,
-            const DeviceAddress& device,
-            const AudioConfig& config,
-            AudioInputFlag flags,
-            AudioSource source,
-            openInputStream_cb _hidl_cb)  override;
-    Return<bool> supportsAudioPatches()  override;
-    Return<void> createAudioPatch(
-            const hidl_vec<AudioPortConfig>& sources,
-            const hidl_vec<AudioPortConfig>& sinks,
-            createAudioPatch_cb _hidl_cb)  override;
-    Return<Result> releaseAudioPatch(int32_t patch)  override;
-    Return<void> getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb)  override;
-    Return<Result> setAudioPortConfig(const AudioPortConfig& config)  override;
-    Return<AudioHwSync> getHwAvSync()  override;
-    Return<Result> setScreenState(bool turnedOn)  override;
-    Return<void> getParameters(
-            const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
-    Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
-    Return<void> debugDump(const hidl_handle& fd)  override;
-
-    // Utility methods for extending interfaces.
-    Result analyzeStatus(const char* funcName, int status);
-    void closeInputStream(audio_stream_in_t* stream);
-    void closeOutputStream(audio_stream_out_t* stream);
-    audio_hw_device_t* device() const { return mDevice; }
-
-  private:
-    audio_hw_device_t *mDevice;
-
-    virtual ~Device();
-
-    // Methods from ParametersUtil.
-    char* halGetParameters(const char* keys) override;
-    int halSetParameters(const char* keysAndValues) override;
-
-    uint32_t version() const { return mDevice->common.version; }
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H
diff --git a/audio/2.0/default/DevicesFactory.cpp b/audio/2.0/default/DevicesFactory.cpp
deleted file mode 100644
index b913bc7..0000000
--- a/audio/2.0/default/DevicesFactory.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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 "DevicesFactoryHAL"
-
-#include <string.h>
-
-#include <android/log.h>
-
-#include "Device.h"
-#include "DevicesFactory.h"
-#include "PrimaryDevice.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-// static
-const char* DevicesFactory::deviceToString(IDevicesFactory::Device device) {
-    switch (device) {
-        case IDevicesFactory::Device::PRIMARY: return AUDIO_HARDWARE_MODULE_ID_PRIMARY;
-        case IDevicesFactory::Device::A2DP: return AUDIO_HARDWARE_MODULE_ID_A2DP;
-        case IDevicesFactory::Device::USB: return AUDIO_HARDWARE_MODULE_ID_USB;
-        case IDevicesFactory::Device::R_SUBMIX: return AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX;
-        case IDevicesFactory::Device::STUB: return AUDIO_HARDWARE_MODULE_ID_STUB;
-    }
-    return nullptr;
-}
-
-// static
-int DevicesFactory::loadAudioInterface(const char *if_name, audio_hw_device_t **dev)
-{
-    const hw_module_t *mod;
-    int rc;
-
-    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
-    if (rc) {
-        ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__,
-                AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
-        goto out;
-    }
-    rc = audio_hw_device_open(mod, dev);
-    if (rc) {
-        ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__,
-                AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
-        goto out;
-    }
-    if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
-        ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
-        rc = -EINVAL;
-        audio_hw_device_close(*dev);
-        goto out;
-    }
-    return OK;
-
-out:
-    *dev = NULL;
-    return rc;
-}
-
-// Methods from ::android::hardware::audio::V2_0::IDevicesFactory follow.
-Return<void> DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb)  {
-    audio_hw_device_t *halDevice;
-    Result retval(Result::INVALID_ARGUMENTS);
-    sp<IDevice> result;
-    const char* moduleName = deviceToString(device);
-    if (moduleName != nullptr) {
-        int halStatus = loadAudioInterface(moduleName, &halDevice);
-        if (halStatus == OK) {
-            if (device == IDevicesFactory::Device::PRIMARY) {
-                result = new PrimaryDevice(halDevice);
-            } else {
-                result = new ::android::hardware::audio::V2_0::implementation::
-                    Device(halDevice);
-            }
-            retval = Result::OK;
-        } else if (halStatus == -EINVAL) {
-            retval = Result::NOT_INITIALIZED;
-        }
-    }
-    _hidl_cb(retval, result);
-    return Void();
-}
-
-IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* /* name */) {
-    return new DevicesFactory();
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
diff --git a/audio/2.0/default/DevicesFactory.h b/audio/2.0/default/DevicesFactory.h
deleted file mode 100644
index b046f9f..0000000
--- a/audio/2.0/default/DevicesFactory.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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_AUDIO_V2_0_DEVICESFACTORY_H
-#define ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H
-
-#include <hardware/audio.h>
-
-#include <android/hardware/audio/2.0/IDevicesFactory.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::V2_0::IDevice;
-using ::android::hardware::audio::V2_0::IDevicesFactory;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct DevicesFactory : public IDevicesFactory {
-    // Methods from ::android::hardware::audio::V2_0::IDevicesFactory follow.
-    Return<void> openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb)  override;
-
-  private:
-    static const char* deviceToString(IDevicesFactory::Device device);
-    static int loadAudioInterface(const char *if_name, audio_hw_device_t **dev);
-
-};
-
-extern "C" IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name);
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H
diff --git a/audio/2.0/default/ParametersUtil.cpp b/audio/2.0/default/ParametersUtil.cpp
deleted file mode 100644
index 2140885..0000000
--- a/audio/2.0/default/ParametersUtil.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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.
- */
-
-#include "ParametersUtil.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-// Static method and not private method to avoid leaking status_t dependency
-static Result getHalStatusToResult(status_t status) {
-    switch (status) {
-        case OK:
-            return Result::OK;
-        case BAD_VALUE:  // Nothing was returned, probably because the HAL does
-                         // not handle it
-            return Result::NOT_SUPPORTED;
-        case INVALID_OPERATION:  // Conversion from string to the requested type
-                                 // failed
-            return Result::INVALID_ARGUMENTS;
-        default:  // Should not happen
-            ALOGW("Unexpected status returned by getParam: %u", status);
-            return Result::INVALID_ARGUMENTS;
-    }
-}
-
-Result ParametersUtil::getParam(const char* name, bool* value) {
-    String8 halValue;
-    Result retval = getParam(name, &halValue);
-    *value = false;
-    if (retval == Result::OK) {
-        if (halValue.empty()) {
-            return Result::NOT_SUPPORTED;
-        }
-        *value = !(halValue == AudioParameter::valueOff);
-    }
-    return retval;
-}
-
-Result ParametersUtil::getParam(const char* name, int* value) {
-    const String8 halName(name);
-    AudioParameter keys;
-    keys.addKey(halName);
-    std::unique_ptr<AudioParameter> params = getParams(keys);
-    return getHalStatusToResult(params->getInt(halName, *value));
-}
-
-Result ParametersUtil::getParam(const char* name, String8* value) {
-    const String8 halName(name);
-    AudioParameter keys;
-    keys.addKey(halName);
-    std::unique_ptr<AudioParameter> params = getParams(keys);
-    return getHalStatusToResult(params->get(halName, *value));
-}
-
-void ParametersUtil::getParametersImpl(
-    const hidl_vec<hidl_string>& keys,
-    std::function<void(Result retval,
-                       const hidl_vec<ParameterValue>& parameters)>
-        cb) {
-    AudioParameter halKeys;
-    for (size_t i = 0; i < keys.size(); ++i) {
-        halKeys.addKey(String8(keys[i].c_str()));
-    }
-    std::unique_ptr<AudioParameter> halValues = getParams(halKeys);
-    Result retval = (keys.size() == 0 || halValues->size() != 0)
-                        ? Result::OK
-                        : Result::NOT_SUPPORTED;
-    hidl_vec<ParameterValue> result;
-    result.resize(halValues->size());
-    String8 halKey, halValue;
-    for (size_t i = 0; i < halValues->size(); ++i) {
-        status_t status = halValues->getAt(i, halKey, halValue);
-        if (status != OK) {
-            result.resize(0);
-            retval = getHalStatusToResult(status);
-            break;
-        }
-        result[i].key = halKey.string();
-        result[i].value = halValue.string();
-    }
-    cb(retval, result);
-}
-
-std::unique_ptr<AudioParameter> ParametersUtil::getParams(
-    const AudioParameter& keys) {
-    String8 paramsAndValues;
-    char* halValues = halGetParameters(keys.keysToString().string());
-    if (halValues != NULL) {
-        paramsAndValues.setTo(halValues);
-        free(halValues);
-    } else {
-        paramsAndValues.clear();
-    }
-    return std::unique_ptr<AudioParameter>(new AudioParameter(paramsAndValues));
-}
-
-Result ParametersUtil::setParam(const char* name, bool value) {
-    AudioParameter param;
-    param.add(String8(name), String8(value ? AudioParameter::valueOn
-                                           : AudioParameter::valueOff));
-    return setParams(param);
-}
-
-Result ParametersUtil::setParam(const char* name, int value) {
-    AudioParameter param;
-    param.addInt(String8(name), value);
-    return setParams(param);
-}
-
-Result ParametersUtil::setParam(const char* name, const char* value) {
-    AudioParameter param;
-    param.add(String8(name), String8(value));
-    return setParams(param);
-}
-
-Result ParametersUtil::setParametersImpl(
-    const hidl_vec<ParameterValue>& parameters) {
-    AudioParameter params;
-    for (size_t i = 0; i < parameters.size(); ++i) {
-        params.add(String8(parameters[i].key.c_str()),
-                   String8(parameters[i].value.c_str()));
-    }
-    return setParams(params);
-}
-
-Result ParametersUtil::setParams(const AudioParameter& param) {
-    int halStatus = halSetParameters(param.toString().string());
-    if (halStatus == OK)
-        return Result::OK;
-    else if (halStatus == -ENOSYS)
-        return Result::INVALID_STATE;
-    else
-        return Result::INVALID_ARGUMENTS;
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
diff --git a/audio/2.0/default/ParametersUtil.h b/audio/2.0/default/ParametersUtil.h
deleted file mode 100644
index 49036dc..0000000
--- a/audio/2.0/default/ParametersUtil.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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_audio_V2_0_ParametersUtil_H_
-#define android_hardware_audio_V2_0_ParametersUtil_H_
-
-#include <functional>
-#include <memory>
-
-#include <android/hardware/audio/2.0/types.h>
-#include <hidl/HidlSupport.h>
-#include <media/AudioParameter.h>
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::V2_0::ParameterValue;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-
-class ParametersUtil {
-  public:
-    Result getParam(const char* name, bool* value);
-    Result getParam(const char* name, int* value);
-    Result getParam(const char* name, String8* value);
-    void getParametersImpl(
-            const hidl_vec<hidl_string>& keys,
-            std::function<void(Result retval, const hidl_vec<ParameterValue>& parameters)> cb);
-    std::unique_ptr<AudioParameter> getParams(const AudioParameter& keys);
-    Result setParam(const char* name, bool value);
-    Result setParam(const char* name, int value);
-    Result setParam(const char* name, const char* value);
-    Result setParametersImpl(const hidl_vec<ParameterValue>& parameters);
-    Result setParams(const AudioParameter& param);
-
-  protected:
-    virtual ~ParametersUtil() {}
-
-    virtual char* halGetParameters(const char* keys) = 0;
-    virtual int halSetParameters(const char* keysAndValues) = 0;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // android_hardware_audio_V2_0_ParametersUtil_H_
diff --git a/audio/2.0/default/PrimaryDevice.cpp b/audio/2.0/default/PrimaryDevice.cpp
deleted file mode 100644
index a4a8206..0000000
--- a/audio/2.0/default/PrimaryDevice.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * 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 "PrimaryDeviceHAL"
-
-#include "PrimaryDevice.h"
-#include "Util.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-PrimaryDevice::PrimaryDevice(audio_hw_device_t* device)
-        : mDevice(new Device(device)) {
-}
-
-PrimaryDevice::~PrimaryDevice() {}
-
-// Methods from ::android::hardware::audio::V2_0::IDevice follow.
-Return<Result> PrimaryDevice::initCheck() {
-    return mDevice->initCheck();
-}
-
-Return<Result> PrimaryDevice::setMasterVolume(float volume) {
-    return mDevice->setMasterVolume(volume);
-}
-
-Return<void> PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) {
-    return mDevice->getMasterVolume(_hidl_cb);
-}
-
-Return<Result> PrimaryDevice::setMicMute(bool mute) {
-    return mDevice->setMicMute(mute);
-}
-
-Return<void> PrimaryDevice::getMicMute(getMicMute_cb _hidl_cb) {
-    return mDevice->getMicMute(_hidl_cb);
-}
-
-Return<Result> PrimaryDevice::setMasterMute(bool mute) {
-    return mDevice->setMasterMute(mute);
-}
-
-Return<void> PrimaryDevice::getMasterMute(getMasterMute_cb _hidl_cb) {
-    return mDevice->getMasterMute(_hidl_cb);
-}
-
-Return<void> PrimaryDevice::getInputBufferSize(const AudioConfig& config,
-                                               getInputBufferSize_cb _hidl_cb) {
-    return mDevice->getInputBufferSize(config, _hidl_cb);
-}
-
-Return<void> PrimaryDevice::openOutputStream(int32_t ioHandle,
-                                             const DeviceAddress& device,
-                                             const AudioConfig& config,
-                                             AudioOutputFlag flags,
-                                             openOutputStream_cb _hidl_cb) {
-    return mDevice->openOutputStream(ioHandle, device, config, flags, _hidl_cb);
-}
-
-Return<void> PrimaryDevice::openInputStream(
-    int32_t ioHandle, const DeviceAddress& device, const AudioConfig& config,
-    AudioInputFlag flags, AudioSource source, openInputStream_cb _hidl_cb) {
-    return mDevice->openInputStream(ioHandle, device, config, flags, source,
-                                    _hidl_cb);
-}
-
-Return<bool> PrimaryDevice::supportsAudioPatches() {
-    return mDevice->supportsAudioPatches();
-}
-
-Return<void> PrimaryDevice::createAudioPatch(
-    const hidl_vec<AudioPortConfig>& sources,
-    const hidl_vec<AudioPortConfig>& sinks, createAudioPatch_cb _hidl_cb) {
-    return mDevice->createAudioPatch(sources, sinks, _hidl_cb);
-}
-
-Return<Result> PrimaryDevice::releaseAudioPatch(int32_t patch) {
-    return mDevice->releaseAudioPatch(patch);
-}
-
-Return<void> PrimaryDevice::getAudioPort(const AudioPort& port,
-                                         getAudioPort_cb _hidl_cb) {
-    return mDevice->getAudioPort(port, _hidl_cb);
-}
-
-Return<Result> PrimaryDevice::setAudioPortConfig(
-    const AudioPortConfig& config) {
-    return mDevice->setAudioPortConfig(config);
-}
-
-Return<AudioHwSync> PrimaryDevice::getHwAvSync() {
-    return mDevice->getHwAvSync();
-}
-
-Return<Result> PrimaryDevice::setScreenState(bool turnedOn) {
-    return mDevice->setScreenState(turnedOn);
-}
-
-Return<void> PrimaryDevice::getParameters(const hidl_vec<hidl_string>& keys,
-                                          getParameters_cb _hidl_cb) {
-    return mDevice->getParameters(keys, _hidl_cb);
-}
-
-Return<Result> PrimaryDevice::setParameters(
-    const hidl_vec<ParameterValue>& parameters) {
-    return mDevice->setParameters(parameters);
-}
-
-Return<void> PrimaryDevice::debugDump(const hidl_handle& fd) {
-    return mDevice->debugDump(fd);
-}
-
-// Methods from ::android::hardware::audio::V2_0::IPrimaryDevice follow.
-Return<Result> PrimaryDevice::setVoiceVolume(float volume) {
-    if (!isGainNormalized(volume)) {
-        ALOGW("Can not set a voice volume (%f) outside [0,1]", volume);
-        return Result::INVALID_ARGUMENTS;
-    }
-    return mDevice->analyzeStatus(
-        "set_voice_volume",
-        mDevice->device()->set_voice_volume(mDevice->device(), volume));
-}
-
-Return<Result> PrimaryDevice::setMode(AudioMode mode) {
-    // INVALID, CURRENT, CNT, MAX are reserved for internal use.
-    // TODO: remove the values from the HIDL interface
-    switch (mode) {
-        case AudioMode::NORMAL:
-        case AudioMode::RINGTONE:
-        case AudioMode::IN_CALL:
-        case AudioMode::IN_COMMUNICATION:
-            break;  // Valid values
-        default:
-            return Result::INVALID_ARGUMENTS;
-    };
-
-    return mDevice->analyzeStatus(
-        "set_mode", mDevice->device()->set_mode(
-                        mDevice->device(), static_cast<audio_mode_t>(mode)));
-}
-
-Return<void> PrimaryDevice::getBtScoNrecEnabled(
-    getBtScoNrecEnabled_cb _hidl_cb) {
-    bool enabled;
-    Result retval = mDevice->getParam(AudioParameter::keyBtNrec, &enabled);
-    _hidl_cb(retval, enabled);
-    return Void();
-}
-
-Return<Result> PrimaryDevice::setBtScoNrecEnabled(bool enabled) {
-    return mDevice->setParam(AudioParameter::keyBtNrec, enabled);
-}
-
-Return<void> PrimaryDevice::getBtScoWidebandEnabled(
-    getBtScoWidebandEnabled_cb _hidl_cb) {
-    bool enabled;
-    Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, &enabled);
-    _hidl_cb(retval, enabled);
-    return Void();
-}
-
-Return<Result> PrimaryDevice::setBtScoWidebandEnabled(bool enabled) {
-    return mDevice->setParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, enabled);
-}
-
-Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) {
-    int halMode;
-    Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_TTY_MODE, &halMode);
-    TtyMode mode = retval == Result::OK ? TtyMode(halMode) : TtyMode::OFF;
-    _hidl_cb(retval, mode);
-    return Void();
-}
-
-Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) {
-    return mDevice->setParam(AUDIO_PARAMETER_KEY_TTY_MODE,
-                             static_cast<int>(mode));
-}
-
-Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) {
-    bool enabled;
-    Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_HAC, &enabled);
-    _hidl_cb(retval, enabled);
-    return Void();
-}
-
-Return<Result> PrimaryDevice::setHacEnabled(bool enabled) {
-    return mDevice->setParam(AUDIO_PARAMETER_KEY_HAC, enabled);
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
diff --git a/audio/2.0/default/PrimaryDevice.h b/audio/2.0/default/PrimaryDevice.h
deleted file mode 100644
index d95511b..0000000
--- a/audio/2.0/default/PrimaryDevice.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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_AUDIO_V2_0_PRIMARYDEVICE_H
-#define ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H
-
-#include <android/hardware/audio/2.0/IPrimaryDevice.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
-
-#include "Device.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioConfig;
-using ::android::hardware::audio::common::V2_0::AudioInputFlag;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
-using ::android::hardware::audio::common::V2_0::AudioPort;
-using ::android::hardware::audio::common::V2_0::AudioPortConfig;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::V2_0::DeviceAddress;
-using ::android::hardware::audio::V2_0::IDevice;
-using ::android::hardware::audio::V2_0::IPrimaryDevice;
-using ::android::hardware::audio::V2_0::IStreamIn;
-using ::android::hardware::audio::V2_0::IStreamOut;
-using ::android::hardware::audio::V2_0::ParameterValue;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct PrimaryDevice : public IPrimaryDevice {
-    explicit PrimaryDevice(audio_hw_device_t* device);
-
-    // Methods from ::android::hardware::audio::V2_0::IDevice follow.
-    Return<Result> initCheck()  override;
-    Return<Result> setMasterVolume(float volume)  override;
-    Return<void> getMasterVolume(getMasterVolume_cb _hidl_cb)  override;
-    Return<Result> setMicMute(bool mute)  override;
-    Return<void> getMicMute(getMicMute_cb _hidl_cb)  override;
-    Return<Result> setMasterMute(bool mute)  override;
-    Return<void> getMasterMute(getMasterMute_cb _hidl_cb)  override;
-    Return<void> getInputBufferSize(
-            const AudioConfig& config, getInputBufferSize_cb _hidl_cb)  override;
-    Return<void> openOutputStream(
-            int32_t ioHandle,
-            const DeviceAddress& device,
-            const AudioConfig& config,
-            AudioOutputFlag flags,
-            openOutputStream_cb _hidl_cb)  override;
-    Return<void> openInputStream(
-            int32_t ioHandle,
-            const DeviceAddress& device,
-            const AudioConfig& config,
-            AudioInputFlag flags,
-            AudioSource source,
-            openInputStream_cb _hidl_cb)  override;
-    Return<bool> supportsAudioPatches()  override;
-    Return<void> createAudioPatch(
-            const hidl_vec<AudioPortConfig>& sources,
-            const hidl_vec<AudioPortConfig>& sinks,
-            createAudioPatch_cb _hidl_cb)  override;
-    Return<Result> releaseAudioPatch(int32_t patch)  override;
-    Return<void> getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb)  override;
-    Return<Result> setAudioPortConfig(const AudioPortConfig& config)  override;
-    Return<AudioHwSync> getHwAvSync()  override;
-    Return<Result> setScreenState(bool turnedOn)  override;
-    Return<void> getParameters(
-            const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
-    Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
-    Return<void> debugDump(const hidl_handle& fd)  override;
-
-    // Methods from ::android::hardware::audio::V2_0::IPrimaryDevice follow.
-    Return<Result> setVoiceVolume(float volume)  override;
-    Return<Result> setMode(AudioMode mode)  override;
-    Return<void> getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb)  override;
-    Return<Result> setBtScoNrecEnabled(bool enabled)  override;
-    Return<void> getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb)  override;
-    Return<Result> setBtScoWidebandEnabled(bool enabled)  override;
-    Return<void> getTtyMode(getTtyMode_cb _hidl_cb)  override;
-    Return<Result> setTtyMode(IPrimaryDevice::TtyMode mode)  override;
-    Return<void> getHacEnabled(getHacEnabled_cb _hidl_cb)  override;
-    Return<Result> setHacEnabled(bool enabled)  override;
-
-  private:
-    sp<Device> mDevice;
-
-    virtual ~PrimaryDevice();
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H
diff --git a/audio/2.0/default/Stream.cpp b/audio/2.0/default/Stream.cpp
deleted file mode 100644
index effdd28..0000000
--- a/audio/2.0/default/Stream.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * 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.
- */
-
-#include <inttypes.h>
-
-#define LOG_TAG "StreamHAL"
-
-#include <hardware/audio.h>
-#include <hardware/audio_effect.h>
-#include <media/TypeConverter.h>
-#include <android/log.h>
-#include <utils/SortedVector.h>
-#include <utils/Vector.h>
-
-#include "Conversions.h"
-#include "EffectMap.h"
-#include "Stream.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-Stream::Stream(audio_stream_t* stream)
-        : mStream(stream) {
-}
-
-Stream::~Stream() {
-    mStream = nullptr;
-}
-
-// static
-Result Stream::analyzeStatus(const char* funcName, int status) {
-    static const std::vector<int> empty;
-    return analyzeStatus(funcName, status, empty);
-}
-
-template <typename T>
-inline bool element_in(T e, const std::vector<T>& v) {
-    return std::find(v.begin(), v.end(), e) != v.end();
-}
-
-// static
-Result Stream::analyzeStatus(const char* funcName, int status,
-                             const std::vector<int>& ignoreErrors) {
-    if (status != 0 && (ignoreErrors.empty() || !element_in(-status, ignoreErrors))) {
-        ALOGW("Error from HAL stream in function %s: %s", funcName, strerror(-status));
-    }
-    switch (status) {
-        case 0: return Result::OK;
-        case -EINVAL: return Result::INVALID_ARGUMENTS;
-        case -ENODATA: return Result::INVALID_STATE;
-        case -ENODEV: return Result::NOT_INITIALIZED;
-        case -ENOSYS: return Result::NOT_SUPPORTED;
-        default: return Result::INVALID_STATE;
-    }
-}
-
-char* Stream::halGetParameters(const char* keys) {
-    return mStream->get_parameters(mStream, keys);
-}
-
-int Stream::halSetParameters(const char* keysAndValues) {
-    return mStream->set_parameters(mStream, keysAndValues);
-}
-
-// Methods from ::android::hardware::audio::V2_0::IStream follow.
-Return<uint64_t> Stream::getFrameSize()  {
-    // Needs to be implemented by interface subclasses. But can't be declared as pure virtual,
-    // since interface subclasses implementation do not inherit from this class.
-    LOG_ALWAYS_FATAL("Stream::getFrameSize is pure abstract");
-    return uint64_t {};
-}
-
-Return<uint64_t> Stream::getFrameCount()  {
-    int halFrameCount;
-    Result retval = getParam(AudioParameter::keyFrameCount, &halFrameCount);
-    return retval == Result::OK ? halFrameCount : 0;
-}
-
-Return<uint64_t> Stream::getBufferSize()  {
-    return mStream->get_buffer_size(mStream);
-}
-
-Return<uint32_t> Stream::getSampleRate()  {
-    return mStream->get_sample_rate(mStream);
-}
-
-Return<void> Stream::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb)  {
-    String8 halListValue;
-    Result result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue);
-    hidl_vec<uint32_t> sampleRates;
-    SortedVector<uint32_t> halSampleRates;
-    if (result == Result::OK) {
-        halSampleRates = samplingRatesFromString(
-                halListValue.string(), AudioParameter::valueListSeparator);
-        sampleRates.setToExternal(halSampleRates.editArray(), halSampleRates.size());
-    }
-    _hidl_cb(sampleRates);
-    return Void();
-}
-
-Return<Result> Stream::setSampleRate(uint32_t sampleRateHz)  {
-    return setParam(AudioParameter::keySamplingRate, static_cast<int>(sampleRateHz));
-}
-
-Return<AudioChannelMask> Stream::getChannelMask()  {
-    return AudioChannelMask(mStream->get_channels(mStream));
-}
-
-Return<void> Stream::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb)  {
-    String8 halListValue;
-    Result result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue);
-    hidl_vec<AudioChannelMask> channelMasks;
-    SortedVector<audio_channel_mask_t> halChannelMasks;
-    if (result == Result::OK) {
-        halChannelMasks = channelMasksFromString(
-                halListValue.string(), AudioParameter::valueListSeparator);
-        channelMasks.resize(halChannelMasks.size());
-        for (size_t i = 0; i < halChannelMasks.size(); ++i) {
-            channelMasks[i] = AudioChannelMask(halChannelMasks[i]);
-        }
-    }
-     _hidl_cb(channelMasks);
-    return Void();
-}
-
-Return<Result> Stream::setChannelMask(AudioChannelMask mask)  {
-    return setParam(AudioParameter::keyChannels, static_cast<int>(mask));
-}
-
-Return<AudioFormat> Stream::getFormat()  {
-    return AudioFormat(mStream->get_format(mStream));
-}
-
-Return<void> Stream::getSupportedFormats(getSupportedFormats_cb _hidl_cb)  {
-    String8 halListValue;
-    Result result = getParam(AudioParameter::keyStreamSupportedFormats, &halListValue);
-    hidl_vec<AudioFormat> formats;
-    Vector<audio_format_t> halFormats;
-    if (result == Result::OK) {
-        halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator);
-        formats.resize(halFormats.size());
-        for (size_t i = 0; i < halFormats.size(); ++i) {
-            formats[i] = AudioFormat(halFormats[i]);
-        }
-    }
-     _hidl_cb(formats);
-    return Void();
-}
-
-Return<Result> Stream::setFormat(AudioFormat format)  {
-    return setParam(AudioParameter::keyFormat, static_cast<int>(format));
-}
-
-Return<void> Stream::getAudioProperties(getAudioProperties_cb _hidl_cb)  {
-    uint32_t halSampleRate = mStream->get_sample_rate(mStream);
-    audio_channel_mask_t halMask = mStream->get_channels(mStream);
-    audio_format_t halFormat = mStream->get_format(mStream);
-    _hidl_cb(halSampleRate, AudioChannelMask(halMask), AudioFormat(halFormat));
-    return Void();
-}
-
-Return<Result> Stream::addEffect(uint64_t effectId)  {
-    effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
-    if (halEffect != NULL) {
-        return analyzeStatus("add_audio_effect", mStream->add_audio_effect(mStream, halEffect));
-    } else {
-        ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId);
-        return Result::INVALID_ARGUMENTS;
-    }
-}
-
-Return<Result> Stream::removeEffect(uint64_t effectId)  {
-    effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
-    if (halEffect != NULL) {
-        return analyzeStatus(
-                "remove_audio_effect", mStream->remove_audio_effect(mStream, halEffect));
-    } else {
-        ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId);
-        return Result::INVALID_ARGUMENTS;
-    }
-}
-
-Return<Result> Stream::standby()  {
-    return analyzeStatus("standby", mStream->standby(mStream));
-}
-
-Return<AudioDevice> Stream::getDevice()  {
-    int device;
-    Result retval = getParam(AudioParameter::keyRouting, &device);
-    return retval == Result::OK ? static_cast<AudioDevice>(device) : AudioDevice::NONE;
-}
-
-Return<Result> Stream::setDevice(const DeviceAddress& address)  {
-    char* halDeviceAddress =
-            audio_device_address_to_parameter(
-                    static_cast<audio_devices_t>(address.device),
-                    deviceAddressToHal(address).c_str());
-    AudioParameter params((String8(halDeviceAddress)));
-    free(halDeviceAddress);
-    params.addInt(
-            String8(AudioParameter::keyRouting), static_cast<audio_devices_t>(address.device));
-    return setParams(params);
-}
-
-Return<Result> Stream::setConnectedState(const DeviceAddress& address, bool connected)  {
-    return setParam(
-            connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect,
-            deviceAddressToHal(address).c_str());
-}
-
-Return<Result> Stream::setHwAvSync(uint32_t hwAvSync)  {
-    return setParam(AudioParameter::keyStreamHwAvSync, static_cast<int>(hwAvSync));
-}
-
-Return<void> Stream::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  {
-    getParametersImpl(keys, _hidl_cb);
-    return Void();
-}
-
-Return<Result> Stream::setParameters(const hidl_vec<ParameterValue>& parameters)  {
-    return setParametersImpl(parameters);
-}
-
-Return<void> Stream::debugDump(const hidl_handle& fd)  {
-    if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
-        analyzeStatus("dump", mStream->dump(mStream, fd->data[0]));
-    }
-    return Void();
-}
-
-Return<Result>  Stream::start() {
-    return Result::NOT_SUPPORTED;
-}
-
-Return<Result>  Stream::stop() {
-    return Result::NOT_SUPPORTED;
-}
-
-Return<void>  Stream::createMmapBuffer(int32_t minSizeFrames __unused,
-                                       createMmapBuffer_cb _hidl_cb) {
-    Result retval(Result::NOT_SUPPORTED);
-    MmapBufferInfo info;
-    _hidl_cb(retval, info);
-    return Void();
-}
-
-Return<void>  Stream::getMmapPosition(getMmapPosition_cb _hidl_cb) {
-    Result retval(Result::NOT_SUPPORTED);
-    MmapPosition position;
-    _hidl_cb(retval, position);
-    return Void();
-}
-
-Return<Result> Stream::close()  {
-    return Result::NOT_SUPPORTED;
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
diff --git a/audio/2.0/default/Stream.h b/audio/2.0/default/Stream.h
deleted file mode 100644
index e29af53..0000000
--- a/audio/2.0/default/Stream.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * 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_AUDIO_V2_0_STREAM_H
-#define ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H
-
-#include <vector>
-
-#include <android/hardware/audio/2.0/IStream.h>
-#include <hardware/audio.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
-
-#include "ParametersUtil.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioChannelMask;
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioFormat;
-using ::android::hardware::audio::V2_0::DeviceAddress;
-using ::android::hardware::audio::V2_0::IStream;
-using ::android::hardware::audio::V2_0::ParameterValue;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct Stream : public IStream, public ParametersUtil {
-    explicit Stream(audio_stream_t* stream);
-
-    /** 1GiB is the maximum buffer size the HAL client is allowed to request.
-     * This value has been chosen to be under SIZE_MAX and still big enough
-     * for all audio use case.
-     * Keep private for 2.0, put in .hal in 2.1
-     */
-    static constexpr uint32_t MAX_BUFFER_SIZE = 2 << 30 /* == 1GiB */;
-
-    // Methods from ::android::hardware::audio::V2_0::IStream follow.
-    Return<uint64_t> getFrameSize()  override;
-    Return<uint64_t> getFrameCount()  override;
-    Return<uint64_t> getBufferSize()  override;
-    Return<uint32_t> getSampleRate()  override;
-    Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb)  override;
-    Return<Result> setSampleRate(uint32_t sampleRateHz)  override;
-    Return<AudioChannelMask> getChannelMask()  override;
-    Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb)  override;
-    Return<Result> setChannelMask(AudioChannelMask mask)  override;
-    Return<AudioFormat> getFormat()  override;
-    Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb)  override;
-    Return<Result> setFormat(AudioFormat format)  override;
-    Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb)  override;
-    Return<Result> addEffect(uint64_t effectId)  override;
-    Return<Result> removeEffect(uint64_t effectId)  override;
-    Return<Result> standby()  override;
-    Return<AudioDevice> getDevice()  override;
-    Return<Result> setDevice(const DeviceAddress& address)  override;
-    Return<Result> setConnectedState(const DeviceAddress& address, bool connected)  override;
-    Return<Result> setHwAvSync(uint32_t hwAvSync)  override;
-    Return<void> getParameters(
-            const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
-    Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
-    Return<void> debugDump(const hidl_handle& fd)  override;
-    Return<Result> start() override;
-    Return<Result> stop() override;
-    Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
-    Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
-    Return<Result> close()  override;
-
-    // Utility methods for extending interfaces.
-    static Result analyzeStatus(const char* funcName, int status);
-    static Result analyzeStatus(const char* funcName, int status,
-                                const std::vector<int>& ignoreErrors);
-
-   private:
-    audio_stream_t *mStream;
-
-    virtual ~Stream();
-
-    // Methods from ParametersUtil.
-    char* halGetParameters(const char* keys) override;
-    int halSetParameters(const char* keysAndValues) override;
-};
-
-
-template <typename T>
-struct StreamMmap : public RefBase {
-    explicit StreamMmap(T* stream) : mStream(stream) {}
-
-    Return<Result> start();
-    Return<Result> stop();
-    Return<void> createMmapBuffer(
-            int32_t minSizeFrames, size_t frameSize, IStream::createMmapBuffer_cb _hidl_cb);
-    Return<void> getMmapPosition(IStream::getMmapPosition_cb _hidl_cb);
-
- private:
-   StreamMmap() {}
-
-   T *mStream;
-};
-
-template <typename T>
-Return<Result> StreamMmap<T>::start() {
-    if (mStream->start == NULL) return Result::NOT_SUPPORTED;
-    int result = mStream->start(mStream);
-    return Stream::analyzeStatus("start", result);
-}
-
-template <typename T>
-Return<Result> StreamMmap<T>::stop() {
-    if (mStream->stop == NULL) return Result::NOT_SUPPORTED;
-    int result = mStream->stop(mStream);
-    return Stream::analyzeStatus("stop", result);
-}
-
-template <typename T>
-Return<void> StreamMmap<T>::createMmapBuffer(int32_t minSizeFrames, size_t frameSize,
-                                             IStream::createMmapBuffer_cb _hidl_cb) {
-    Result retval(Result::NOT_SUPPORTED);
-    MmapBufferInfo info;
-    native_handle_t* hidlHandle = nullptr;
-
-    if (mStream->create_mmap_buffer != NULL) {
-        struct audio_mmap_buffer_info halInfo;
-        retval = Stream::analyzeStatus(
-                "create_mmap_buffer",
-                mStream->create_mmap_buffer(mStream, minSizeFrames, &halInfo));
-        if (retval == Result::OK) {
-            hidlHandle = native_handle_create(1, 0);
-            hidlHandle->data[0] = halInfo.shared_memory_fd;
-            info.sharedMemory = hidl_memory("audio_buffer", hidlHandle,
-                                            frameSize *halInfo.buffer_size_frames);
-            info.bufferSizeFrames = halInfo.buffer_size_frames;
-            info.burstSizeFrames = halInfo.burst_size_frames;
-        }
-    }
-    _hidl_cb(retval, info);
-    if (hidlHandle != nullptr) {
-        native_handle_delete(hidlHandle);
-    }
-    return Void();
-}
-
-template <typename T>
-Return<void> StreamMmap<T>::getMmapPosition(IStream::getMmapPosition_cb _hidl_cb) {
-    Result retval(Result::NOT_SUPPORTED);
-    MmapPosition position;
-
-    if (mStream->get_mmap_position != NULL) {
-        struct audio_mmap_position halPosition;
-        retval = Stream::analyzeStatus(
-                "get_mmap_position",
-                mStream->get_mmap_position(mStream, &halPosition));
-        if (retval == Result::OK) {
-            position.timeNanoseconds = halPosition.time_nanoseconds;
-            position.positionFrames = halPosition.position_frames;
-        }
-    }
-    _hidl_cb(retval, position);
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H
diff --git a/audio/2.0/default/StreamIn.cpp b/audio/2.0/default/StreamIn.cpp
deleted file mode 100644
index 61d5d8e..0000000
--- a/audio/2.0/default/StreamIn.cpp
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * 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 "StreamInHAL"
-//#define LOG_NDEBUG 0
-#define ATRACE_TAG ATRACE_TAG_AUDIO
-
-#include <android/log.h>
-#include <hardware/audio.h>
-#include <utils/Trace.h>
-#include <memory>
-
-#include "StreamIn.h"
-#include "Util.h"
-
-using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::ThreadInfo;
-
-namespace {
-
-class ReadThread : public Thread {
-   public:
-    // ReadThread's lifespan never exceeds StreamIn's lifespan.
-    ReadThread(std::atomic<bool>* stop, audio_stream_in_t* stream,
-               StreamIn::CommandMQ* commandMQ, StreamIn::DataMQ* dataMQ,
-               StreamIn::StatusMQ* statusMQ, EventFlag* efGroup)
-        : Thread(false /*canCallJava*/),
-          mStop(stop),
-          mStream(stream),
-          mCommandMQ(commandMQ),
-          mDataMQ(dataMQ),
-          mStatusMQ(statusMQ),
-          mEfGroup(efGroup),
-          mBuffer(nullptr) {}
-    bool init() {
-        mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
-        return mBuffer != nullptr;
-    }
-    virtual ~ReadThread() {}
-
-   private:
-    std::atomic<bool>* mStop;
-    audio_stream_in_t* mStream;
-    StreamIn::CommandMQ* mCommandMQ;
-    StreamIn::DataMQ* mDataMQ;
-    StreamIn::StatusMQ* mStatusMQ;
-    EventFlag* mEfGroup;
-    std::unique_ptr<uint8_t[]> mBuffer;
-    IStreamIn::ReadParameters mParameters;
-    IStreamIn::ReadStatus mStatus;
-
-    bool threadLoop() override;
-
-    void doGetCapturePosition();
-    void doRead();
-};
-
-void ReadThread::doRead() {
-    size_t availableToWrite = mDataMQ->availableToWrite();
-    size_t requestedToRead = mParameters.params.read;
-    if (requestedToRead > availableToWrite) {
-        ALOGW(
-            "truncating read data from %d to %d due to insufficient data queue "
-            "space",
-            (int32_t)requestedToRead, (int32_t)availableToWrite);
-        requestedToRead = availableToWrite;
-    }
-    ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
-    mStatus.retval = Result::OK;
-    if (readResult >= 0) {
-        mStatus.reply.read = readResult;
-        if (!mDataMQ->write(&mBuffer[0], readResult)) {
-            ALOGW("data message queue write failed");
-        }
-    } else {
-        mStatus.retval = Stream::analyzeStatus("read", readResult);
-    }
-}
-
-void ReadThread::doGetCapturePosition() {
-    mStatus.retval = StreamIn::getCapturePositionImpl(
-        mStream, &mStatus.reply.capturePosition.frames,
-        &mStatus.reply.capturePosition.time);
-}
-
-bool ReadThread::threadLoop() {
-    // This implementation doesn't return control back to the Thread until it
-    // decides to stop,
-    // as the Thread uses mutexes, and this can lead to priority inversion.
-    while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
-        uint32_t efState = 0;
-        mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL),
-                       &efState);
-        if (!(efState &
-              static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
-            continue;  // Nothing to do.
-        }
-        if (!mCommandMQ->read(&mParameters)) {
-            continue;  // Nothing to do.
-        }
-        mStatus.replyTo = mParameters.command;
-        switch (mParameters.command) {
-            case IStreamIn::ReadCommand::READ:
-                doRead();
-                break;
-            case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
-                doGetCapturePosition();
-                break;
-            default:
-                ALOGE("Unknown read thread command code %d",
-                      mParameters.command);
-                mStatus.retval = Result::NOT_SUPPORTED;
-                break;
-        }
-        if (!mStatusMQ->write(&mStatus)) {
-            ALOGW("status message queue write failed");
-        }
-        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
-    }
-
-    return false;
-}
-
-}  // namespace
-
-StreamIn::StreamIn(const sp<Device>& device, audio_stream_in_t* stream)
-    : mIsClosed(false),
-      mDevice(device),
-      mStream(stream),
-      mStreamCommon(new Stream(&stream->common)),
-      mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
-      mEfGroup(nullptr),
-      mStopReadThread(false) {}
-
-StreamIn::~StreamIn() {
-    ATRACE_CALL();
-    close();
-    if (mReadThread.get()) {
-        ATRACE_NAME("mReadThread->join");
-        status_t status = mReadThread->join();
-        ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
-    }
-    if (mEfGroup) {
-        status_t status = EventFlag::deleteEventFlag(&mEfGroup);
-        ALOGE_IF(status, "read MQ event flag deletion error: %s",
-                 strerror(-status));
-    }
-    mDevice->closeInputStream(mStream);
-    mStream = nullptr;
-}
-
-// Methods from ::android::hardware::audio::V2_0::IStream follow.
-Return<uint64_t> StreamIn::getFrameSize() {
-    return audio_stream_in_frame_size(mStream);
-}
-
-Return<uint64_t> StreamIn::getFrameCount() {
-    return mStreamCommon->getFrameCount();
-}
-
-Return<uint64_t> StreamIn::getBufferSize() {
-    return mStreamCommon->getBufferSize();
-}
-
-Return<uint32_t> StreamIn::getSampleRate() {
-    return mStreamCommon->getSampleRate();
-}
-
-Return<void> StreamIn::getSupportedSampleRates(
-    getSupportedSampleRates_cb _hidl_cb) {
-    return mStreamCommon->getSupportedSampleRates(_hidl_cb);
-}
-
-Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
-    return mStreamCommon->setSampleRate(sampleRateHz);
-}
-
-Return<AudioChannelMask> StreamIn::getChannelMask() {
-    return mStreamCommon->getChannelMask();
-}
-
-Return<void> StreamIn::getSupportedChannelMasks(
-    getSupportedChannelMasks_cb _hidl_cb) {
-    return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
-}
-
-Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
-    return mStreamCommon->setChannelMask(mask);
-}
-
-Return<AudioFormat> StreamIn::getFormat() {
-    return mStreamCommon->getFormat();
-}
-
-Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
-    return mStreamCommon->getSupportedFormats(_hidl_cb);
-}
-
-Return<Result> StreamIn::setFormat(AudioFormat format) {
-    return mStreamCommon->setFormat(format);
-}
-
-Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
-    return mStreamCommon->getAudioProperties(_hidl_cb);
-}
-
-Return<Result> StreamIn::addEffect(uint64_t effectId) {
-    return mStreamCommon->addEffect(effectId);
-}
-
-Return<Result> StreamIn::removeEffect(uint64_t effectId) {
-    return mStreamCommon->removeEffect(effectId);
-}
-
-Return<Result> StreamIn::standby() {
-    return mStreamCommon->standby();
-}
-
-Return<AudioDevice> StreamIn::getDevice() {
-    return mStreamCommon->getDevice();
-}
-
-Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
-    return mStreamCommon->setDevice(address);
-}
-
-Return<Result> StreamIn::setConnectedState(const DeviceAddress& address,
-                                           bool connected) {
-    return mStreamCommon->setConnectedState(address, connected);
-}
-
-Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
-    return mStreamCommon->setHwAvSync(hwAvSync);
-}
-
-Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys,
-                                     getParameters_cb _hidl_cb) {
-    return mStreamCommon->getParameters(keys, _hidl_cb);
-}
-
-Return<Result> StreamIn::setParameters(
-    const hidl_vec<ParameterValue>& parameters) {
-    return mStreamCommon->setParameters(parameters);
-}
-
-Return<void> StreamIn::debugDump(const hidl_handle& fd) {
-    return mStreamCommon->debugDump(fd);
-}
-
-Return<Result> StreamIn::start() {
-    return mStreamMmap->start();
-}
-
-Return<Result> StreamIn::stop() {
-    return mStreamMmap->stop();
-}
-
-Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames,
-                                        createMmapBuffer_cb _hidl_cb) {
-    return mStreamMmap->createMmapBuffer(
-        minSizeFrames, audio_stream_in_frame_size(mStream), _hidl_cb);
-}
-
-Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
-    return mStreamMmap->getMmapPosition(_hidl_cb);
-}
-
-Return<Result> StreamIn::close() {
-    if (mIsClosed) return Result::INVALID_STATE;
-    mIsClosed = true;
-    if (mReadThread.get()) {
-        mStopReadThread.store(true, std::memory_order_release);
-    }
-    if (mEfGroup) {
-        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
-    }
-    return Result::OK;
-}
-
-// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
-Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
-    int halSource;
-    Result retval =
-        mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
-    AudioSource source(AudioSource::DEFAULT);
-    if (retval == Result::OK) {
-        source = AudioSource(halSource);
-    }
-    _hidl_cb(retval, source);
-    return Void();
-}
-
-Return<Result> StreamIn::setGain(float gain) {
-    if (!isGainNormalized(gain)) {
-        ALOGW("Can not set a stream input gain (%f) outside [0,1]", gain);
-        return Result::INVALID_ARGUMENTS;
-    }
-    return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
-}
-
-Return<void> StreamIn::prepareForReading(uint32_t frameSize,
-                                         uint32_t framesCount,
-                                         prepareForReading_cb _hidl_cb) {
-    status_t status;
-    ThreadInfo threadInfo = {0, 0};
-
-    // Wrap the _hidl_cb to return an error
-    auto sendError = [&threadInfo, &_hidl_cb](Result result) {
-        _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(),
-                 StatusMQ::Descriptor(), threadInfo);
-
-    };
-
-    // Create message queues.
-    if (mDataMQ) {
-        ALOGE("the client attempts to call prepareForReading twice");
-        sendError(Result::INVALID_STATE);
-        return Void();
-    }
-    std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
-
-    // Check frameSize and framesCount
-    if (frameSize == 0 || framesCount == 0) {
-        ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize,
-              framesCount);
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-
-    if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) {
-        ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount,
-              Stream::MAX_BUFFER_SIZE);
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-    std::unique_ptr<DataMQ> tempDataMQ(
-        new DataMQ(frameSize * framesCount, true /* EventFlag */));
-
-    std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
-    if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() ||
-        !tempStatusMQ->isValid()) {
-        ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
-        ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
-        ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-    EventFlag* tempRawEfGroup{};
-    status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(),
-                                        &tempRawEfGroup);
-    std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup(
-        tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); });
-    if (status != OK || !tempElfGroup) {
-        ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-
-    // Create and launch the thread.
-    auto tempReadThread = std::make_unique<ReadThread>(
-        &mStopReadThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
-        tempStatusMQ.get(), tempElfGroup.get());
-    if (!tempReadThread->init()) {
-        ALOGW("failed to start reader thread: %s", strerror(-status));
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-    status = tempReadThread->run("reader", PRIORITY_URGENT_AUDIO);
-    if (status != OK) {
-        ALOGW("failed to start reader thread: %s", strerror(-status));
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-
-    mCommandMQ = std::move(tempCommandMQ);
-    mDataMQ = std::move(tempDataMQ);
-    mStatusMQ = std::move(tempStatusMQ);
-    mReadThread = tempReadThread.release();
-    mEfGroup = tempElfGroup.release();
-    threadInfo.pid = getpid();
-    threadInfo.tid = mReadThread->getTid();
-    _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(),
-             *mStatusMQ->getDesc(), threadInfo);
-    return Void();
-}
-
-Return<uint32_t> StreamIn::getInputFramesLost() {
-    return mStream->get_input_frames_lost(mStream);
-}
-
-// static
-Result StreamIn::getCapturePositionImpl(audio_stream_in_t* stream,
-                                        uint64_t* frames, uint64_t* time) {
-    // HAL may have a stub function, always returning ENOSYS, don't
-    // spam the log in this case.
-    static const std::vector<int> ignoredErrors{ENOSYS};
-    Result retval(Result::NOT_SUPPORTED);
-    if (stream->get_capture_position == NULL) return retval;
-    int64_t halFrames, halTime;
-    retval = Stream::analyzeStatus("get_capture_position",
-                                   stream->get_capture_position(stream, &halFrames, &halTime),
-                                   ignoredErrors);
-    if (retval == Result::OK) {
-        *frames = halFrames;
-        *time = halTime;
-    }
-    return retval;
-};
-
-Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
-    uint64_t frames = 0, time = 0;
-    Result retval = getCapturePositionImpl(mStream, &frames, &time);
-    _hidl_cb(retval, frames, time);
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
diff --git a/audio/2.0/default/StreamIn.h b/audio/2.0/default/StreamIn.h
deleted file mode 100644
index 950d68f..0000000
--- a/audio/2.0/default/StreamIn.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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_AUDIO_V2_0_STREAMIN_H
-#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
-
-#include <atomic>
-#include <memory>
-
-#include <android/hardware/audio/2.0/IStreamIn.h>
-#include <hidl/MQDescriptor.h>
-#include <fmq/EventFlag.h>
-#include <fmq/MessageQueue.h>
-#include <hidl/Status.h>
-#include <utils/Thread.h>
-
-#include "Device.h"
-#include "Stream.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioChannelMask;
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioFormat;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::V2_0::DeviceAddress;
-using ::android::hardware::audio::V2_0::IStream;
-using ::android::hardware::audio::V2_0::IStreamIn;
-using ::android::hardware::audio::V2_0::ParameterValue;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct StreamIn : public IStreamIn {
-    typedef MessageQueue<ReadParameters, kSynchronizedReadWrite> CommandMQ;
-    typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
-    typedef MessageQueue<ReadStatus, kSynchronizedReadWrite> StatusMQ;
-
-    StreamIn(const sp<Device>& device, audio_stream_in_t* stream);
-
-    // Methods from ::android::hardware::audio::V2_0::IStream follow.
-    Return<uint64_t> getFrameSize()  override;
-    Return<uint64_t> getFrameCount()  override;
-    Return<uint64_t> getBufferSize()  override;
-    Return<uint32_t> getSampleRate()  override;
-    Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb)  override;
-    Return<Result> setSampleRate(uint32_t sampleRateHz)  override;
-    Return<AudioChannelMask> getChannelMask()  override;
-    Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb)  override;
-    Return<Result> setChannelMask(AudioChannelMask mask)  override;
-    Return<AudioFormat> getFormat()  override;
-    Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb)  override;
-    Return<Result> setFormat(AudioFormat format)  override;
-    Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb)  override;
-    Return<Result> addEffect(uint64_t effectId)  override;
-    Return<Result> removeEffect(uint64_t effectId)  override;
-    Return<Result> standby()  override;
-    Return<AudioDevice> getDevice()  override;
-    Return<Result> setDevice(const DeviceAddress& address)  override;
-    Return<Result> setConnectedState(const DeviceAddress& address, bool connected)  override;
-    Return<Result> setHwAvSync(uint32_t hwAvSync)  override;
-    Return<void> getParameters(
-            const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
-    Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
-    Return<void> debugDump(const hidl_handle& fd)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
-    Return<void> getAudioSource(getAudioSource_cb _hidl_cb)  override;
-    Return<Result> setGain(float gain)  override;
-    Return<void> prepareForReading(
-            uint32_t frameSize, uint32_t framesCount, prepareForReading_cb _hidl_cb)  override;
-    Return<uint32_t> getInputFramesLost()  override;
-    Return<void> getCapturePosition(getCapturePosition_cb _hidl_cb)  override;
-    Return<Result> start() override;
-    Return<Result> stop() override;
-    Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
-    Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
-
-    static Result getCapturePositionImpl(
-            audio_stream_in_t *stream, uint64_t *frames, uint64_t *time);
-
-  private:
-    bool mIsClosed;
-    const sp<Device> mDevice;
-    audio_stream_in_t *mStream;
-    const sp<Stream> mStreamCommon;
-    const sp<StreamMmap<audio_stream_in_t>> mStreamMmap;
-    std::unique_ptr<CommandMQ> mCommandMQ;
-    std::unique_ptr<DataMQ> mDataMQ;
-    std::unique_ptr<StatusMQ> mStatusMQ;
-    EventFlag* mEfGroup;
-    std::atomic<bool> mStopReadThread;
-    sp<Thread> mReadThread;
-
-    virtual ~StreamIn();
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp
deleted file mode 100644
index 49a6b12..0000000
--- a/audio/2.0/default/StreamOut.cpp
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- * 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 "StreamOutHAL"
-//#define LOG_NDEBUG 0
-#define ATRACE_TAG ATRACE_TAG_AUDIO
-
-#include <memory>
-
-#include <android/log.h>
-#include <hardware/audio.h>
-#include <utils/Trace.h>
-
-#include "StreamOut.h"
-#include "Util.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::ThreadInfo;
-
-namespace {
-
-class WriteThread : public Thread {
-   public:
-    // WriteThread's lifespan never exceeds StreamOut's lifespan.
-    WriteThread(std::atomic<bool>* stop, audio_stream_out_t* stream,
-                StreamOut::CommandMQ* commandMQ, StreamOut::DataMQ* dataMQ,
-                StreamOut::StatusMQ* statusMQ, EventFlag* efGroup)
-        : Thread(false /*canCallJava*/),
-          mStop(stop),
-          mStream(stream),
-          mCommandMQ(commandMQ),
-          mDataMQ(dataMQ),
-          mStatusMQ(statusMQ),
-          mEfGroup(efGroup),
-          mBuffer(nullptr) {}
-    bool init() {
-        mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
-        return mBuffer != nullptr;
-    }
-    virtual ~WriteThread() {}
-
-   private:
-    std::atomic<bool>* mStop;
-    audio_stream_out_t* mStream;
-    StreamOut::CommandMQ* mCommandMQ;
-    StreamOut::DataMQ* mDataMQ;
-    StreamOut::StatusMQ* mStatusMQ;
-    EventFlag* mEfGroup;
-    std::unique_ptr<uint8_t[]> mBuffer;
-    IStreamOut::WriteStatus mStatus;
-
-    bool threadLoop() override;
-
-    void doGetLatency();
-    void doGetPresentationPosition();
-    void doWrite();
-};
-
-void WriteThread::doWrite() {
-    const size_t availToRead = mDataMQ->availableToRead();
-    mStatus.retval = Result::OK;
-    mStatus.reply.written = 0;
-    if (mDataMQ->read(&mBuffer[0], availToRead)) {
-        ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
-        if (writeResult >= 0) {
-            mStatus.reply.written = writeResult;
-        } else {
-            mStatus.retval = Stream::analyzeStatus("write", writeResult);
-        }
-    }
-}
-
-void WriteThread::doGetPresentationPosition() {
-    mStatus.retval = StreamOut::getPresentationPositionImpl(
-        mStream, &mStatus.reply.presentationPosition.frames,
-        &mStatus.reply.presentationPosition.timeStamp);
-}
-
-void WriteThread::doGetLatency() {
-    mStatus.retval = Result::OK;
-    mStatus.reply.latencyMs = mStream->get_latency(mStream);
-}
-
-bool WriteThread::threadLoop() {
-    // This implementation doesn't return control back to the Thread until it
-    // decides to stop,
-    // as the Thread uses mutexes, and this can lead to priority inversion.
-    while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
-        uint32_t efState = 0;
-        mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY),
-                       &efState);
-        if (!(efState &
-              static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) {
-            continue;  // Nothing to do.
-        }
-        if (!mCommandMQ->read(&mStatus.replyTo)) {
-            continue;  // Nothing to do.
-        }
-        switch (mStatus.replyTo) {
-            case IStreamOut::WriteCommand::WRITE:
-                doWrite();
-                break;
-            case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION:
-                doGetPresentationPosition();
-                break;
-            case IStreamOut::WriteCommand::GET_LATENCY:
-                doGetLatency();
-                break;
-            default:
-                ALOGE("Unknown write thread command code %d", mStatus.replyTo);
-                mStatus.retval = Result::NOT_SUPPORTED;
-                break;
-        }
-        if (!mStatusMQ->write(&mStatus)) {
-            ALOGE("status message queue write failed");
-        }
-        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
-    }
-
-    return false;
-}
-
-}  // namespace
-
-StreamOut::StreamOut(const sp<Device>& device, audio_stream_out_t* stream)
-    : mIsClosed(false),
-      mDevice(device),
-      mStream(stream),
-      mStreamCommon(new Stream(&stream->common)),
-      mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)),
-      mEfGroup(nullptr),
-      mStopWriteThread(false) {}
-
-StreamOut::~StreamOut() {
-    ATRACE_CALL();
-    close();
-    if (mWriteThread.get()) {
-        ATRACE_NAME("mWriteThread->join");
-        status_t status = mWriteThread->join();
-        ALOGE_IF(status, "write thread exit error: %s", strerror(-status));
-    }
-    if (mEfGroup) {
-        status_t status = EventFlag::deleteEventFlag(&mEfGroup);
-        ALOGE_IF(status, "write MQ event flag deletion error: %s",
-                 strerror(-status));
-    }
-    mCallback.clear();
-    mDevice->closeOutputStream(mStream);
-    // Closing the output stream in the HAL waits for the callback to finish,
-    // and joins the callback thread. Thus is it guaranteed that the callback
-    // thread will not be accessing our object anymore.
-    mStream = nullptr;
-}
-
-// Methods from ::android::hardware::audio::V2_0::IStream follow.
-Return<uint64_t> StreamOut::getFrameSize() {
-    return audio_stream_out_frame_size(mStream);
-}
-
-Return<uint64_t> StreamOut::getFrameCount() {
-    return mStreamCommon->getFrameCount();
-}
-
-Return<uint64_t> StreamOut::getBufferSize() {
-    return mStreamCommon->getBufferSize();
-}
-
-Return<uint32_t> StreamOut::getSampleRate() {
-    return mStreamCommon->getSampleRate();
-}
-
-Return<void> StreamOut::getSupportedSampleRates(
-    getSupportedSampleRates_cb _hidl_cb) {
-    return mStreamCommon->getSupportedSampleRates(_hidl_cb);
-}
-
-Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) {
-    return mStreamCommon->setSampleRate(sampleRateHz);
-}
-
-Return<AudioChannelMask> StreamOut::getChannelMask() {
-    return mStreamCommon->getChannelMask();
-}
-
-Return<void> StreamOut::getSupportedChannelMasks(
-    getSupportedChannelMasks_cb _hidl_cb) {
-    return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
-}
-
-Return<Result> StreamOut::setChannelMask(AudioChannelMask mask) {
-    return mStreamCommon->setChannelMask(mask);
-}
-
-Return<AudioFormat> StreamOut::getFormat() {
-    return mStreamCommon->getFormat();
-}
-
-Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
-    return mStreamCommon->getSupportedFormats(_hidl_cb);
-}
-
-Return<Result> StreamOut::setFormat(AudioFormat format) {
-    return mStreamCommon->setFormat(format);
-}
-
-Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
-    return mStreamCommon->getAudioProperties(_hidl_cb);
-}
-
-Return<Result> StreamOut::addEffect(uint64_t effectId) {
-    return mStreamCommon->addEffect(effectId);
-}
-
-Return<Result> StreamOut::removeEffect(uint64_t effectId) {
-    return mStreamCommon->removeEffect(effectId);
-}
-
-Return<Result> StreamOut::standby() {
-    return mStreamCommon->standby();
-}
-
-Return<AudioDevice> StreamOut::getDevice() {
-    return mStreamCommon->getDevice();
-}
-
-Return<Result> StreamOut::setDevice(const DeviceAddress& address) {
-    return mStreamCommon->setDevice(address);
-}
-
-Return<Result> StreamOut::setConnectedState(const DeviceAddress& address,
-                                            bool connected) {
-    return mStreamCommon->setConnectedState(address, connected);
-}
-
-Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
-    return mStreamCommon->setHwAvSync(hwAvSync);
-}
-
-Return<void> StreamOut::getParameters(const hidl_vec<hidl_string>& keys,
-                                      getParameters_cb _hidl_cb) {
-    return mStreamCommon->getParameters(keys, _hidl_cb);
-}
-
-Return<Result> StreamOut::setParameters(
-    const hidl_vec<ParameterValue>& parameters) {
-    return mStreamCommon->setParameters(parameters);
-}
-
-Return<void> StreamOut::debugDump(const hidl_handle& fd) {
-    return mStreamCommon->debugDump(fd);
-}
-
-Return<Result> StreamOut::close() {
-    if (mIsClosed) return Result::INVALID_STATE;
-    mIsClosed = true;
-    if (mWriteThread.get()) {
-        mStopWriteThread.store(true, std::memory_order_release);
-    }
-    if (mEfGroup) {
-        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
-    }
-    return Result::OK;
-}
-
-// Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
-Return<uint32_t> StreamOut::getLatency() {
-    return mStream->get_latency(mStream);
-}
-
-Return<Result> StreamOut::setVolume(float left, float right) {
-    if (mStream->set_volume == NULL) {
-        return Result::NOT_SUPPORTED;
-    }
-    if (!isGainNormalized(left)) {
-        ALOGW("Can not set a stream output volume {%f, %f} outside [0,1]", left,
-              right);
-        return Result::INVALID_ARGUMENTS;
-    }
-    return Stream::analyzeStatus("set_volume",
-                                 mStream->set_volume(mStream, left, right));
-}
-
-Return<void> StreamOut::prepareForWriting(uint32_t frameSize,
-                                          uint32_t framesCount,
-                                          prepareForWriting_cb _hidl_cb) {
-    status_t status;
-    ThreadInfo threadInfo = {0, 0};
-
-    // Wrap the _hidl_cb to return an error
-    auto sendError = [&threadInfo, &_hidl_cb](Result result) {
-        _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(),
-                 StatusMQ::Descriptor(), threadInfo);
-
-    };
-
-    // Create message queues.
-    if (mDataMQ) {
-        ALOGE("the client attempts to call prepareForWriting twice");
-        sendError(Result::INVALID_STATE);
-        return Void();
-    }
-    std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
-
-    // Check frameSize and framesCount
-    if (frameSize == 0 || framesCount == 0) {
-        ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize,
-              framesCount);
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-    if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) {
-        ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount,
-              Stream::MAX_BUFFER_SIZE);
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-    std::unique_ptr<DataMQ> tempDataMQ(
-        new DataMQ(frameSize * framesCount, true /* EventFlag */));
-
-    std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
-    if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() ||
-        !tempStatusMQ->isValid()) {
-        ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
-        ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
-        ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-    EventFlag* tempRawEfGroup{};
-    status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(),
-                                        &tempRawEfGroup);
-    std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup(
-        tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); });
-    if (status != OK || !tempElfGroup) {
-        ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-
-    // Create and launch the thread.
-    auto tempWriteThread = std::make_unique<WriteThread>(
-        &mStopWriteThread, mStream, tempCommandMQ.get(), tempDataMQ.get(),
-        tempStatusMQ.get(), tempElfGroup.get());
-    if (!tempWriteThread->init()) {
-        ALOGW("failed to start writer thread: %s", strerror(-status));
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-    status = tempWriteThread->run("writer", PRIORITY_URGENT_AUDIO);
-    if (status != OK) {
-        ALOGW("failed to start writer thread: %s", strerror(-status));
-        sendError(Result::INVALID_ARGUMENTS);
-        return Void();
-    }
-
-    mCommandMQ = std::move(tempCommandMQ);
-    mDataMQ = std::move(tempDataMQ);
-    mStatusMQ = std::move(tempStatusMQ);
-    mWriteThread = tempWriteThread.release();
-    mEfGroup = tempElfGroup.release();
-    threadInfo.pid = getpid();
-    threadInfo.tid = mWriteThread->getTid();
-    _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(),
-             *mStatusMQ->getDesc(), threadInfo);
-    return Void();
-}
-
-Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
-    uint32_t halDspFrames;
-    Result retval = Stream::analyzeStatus(
-        "get_render_position",
-        mStream->get_render_position(mStream, &halDspFrames));
-    _hidl_cb(retval, halDspFrames);
-    return Void();
-}
-
-Return<void> StreamOut::getNextWriteTimestamp(
-    getNextWriteTimestamp_cb _hidl_cb) {
-    Result retval(Result::NOT_SUPPORTED);
-    int64_t timestampUs = 0;
-    if (mStream->get_next_write_timestamp != NULL) {
-        retval = Stream::analyzeStatus(
-            "get_next_write_timestamp",
-            mStream->get_next_write_timestamp(mStream, &timestampUs));
-    }
-    _hidl_cb(retval, timestampUs);
-    return Void();
-}
-
-Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
-    if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
-    // Safe to pass 'this' because it is guaranteed that the callback thread
-    // is joined prior to exit from StreamOut's destructor.
-    int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this);
-    if (result == 0) {
-        mCallback = callback;
-    }
-    return Stream::analyzeStatus("set_callback", result);
-}
-
-Return<Result> StreamOut::clearCallback() {
-    if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
-    mCallback.clear();
-    return Result::OK;
-}
-
-// static
-int StreamOut::asyncCallback(stream_callback_event_t event, void*,
-                             void* cookie) {
-    // It is guaranteed that the callback thread is joined prior
-    // to exiting from StreamOut's destructor. Must *not* use sp<StreamOut>
-    // here because it can make this code the last owner of StreamOut,
-    // and an attempt to run the destructor on the callback thread
-    // will cause a deadlock in the legacy HAL code.
-    StreamOut *self = reinterpret_cast<StreamOut*>(cookie);
-    // It's correct to hold an sp<> to callback because the reference
-    // in the StreamOut instance can be cleared in the meantime. There is
-    // no difference on which thread to run IStreamOutCallback's destructor.
-    sp<IStreamOutCallback> callback = self->mCallback;
-    if (callback.get() == nullptr) return 0;
-    ALOGV("asyncCallback() event %d", event);
-    switch (event) {
-        case STREAM_CBK_EVENT_WRITE_READY:
-            callback->onWriteReady();
-            break;
-        case STREAM_CBK_EVENT_DRAIN_READY:
-            callback->onDrainReady();
-            break;
-        case STREAM_CBK_EVENT_ERROR:
-            callback->onError();
-            break;
-        default:
-            ALOGW("asyncCallback() unknown event %d", event);
-            break;
-    }
-    return 0;
-}
-
-Return<void> StreamOut::supportsPauseAndResume(
-    supportsPauseAndResume_cb _hidl_cb) {
-    _hidl_cb(mStream->pause != NULL, mStream->resume != NULL);
-    return Void();
-}
-
-Return<Result> StreamOut::pause() {
-    return mStream->pause != NULL
-               ? Stream::analyzeStatus("pause", mStream->pause(mStream))
-               : Result::NOT_SUPPORTED;
-}
-
-Return<Result> StreamOut::resume() {
-    return mStream->resume != NULL
-               ? Stream::analyzeStatus("resume", mStream->resume(mStream))
-               : Result::NOT_SUPPORTED;
-}
-
-Return<bool> StreamOut::supportsDrain() {
-    return mStream->drain != NULL;
-}
-
-Return<Result> StreamOut::drain(AudioDrain type) {
-    return mStream->drain != NULL
-               ? Stream::analyzeStatus(
-                     "drain",
-                     mStream->drain(mStream,
-                                    static_cast<audio_drain_type_t>(type)))
-               : Result::NOT_SUPPORTED;
-}
-
-Return<Result> StreamOut::flush() {
-    return mStream->flush != NULL
-               ? Stream::analyzeStatus("flush", mStream->flush(mStream))
-               : Result::NOT_SUPPORTED;
-}
-
-// static
-Result StreamOut::getPresentationPositionImpl(audio_stream_out_t* stream,
-                                              uint64_t* frames,
-                                              TimeSpec* timeStamp) {
-    // Don't logspam on EINVAL--it's normal for get_presentation_position
-    // to return it sometimes. EAGAIN may be returned by A2DP audio HAL
-    // implementation. ENODATA can also be reported while the writer is
-    // continuously querying it, but the stream has been stopped.
-    static const std::vector<int> ignoredErrors{EINVAL, EAGAIN, ENODATA};
-    Result retval(Result::NOT_SUPPORTED);
-    if (stream->get_presentation_position == NULL) return retval;
-    struct timespec halTimeStamp;
-    retval = Stream::analyzeStatus("get_presentation_position",
-                                   stream->get_presentation_position(stream, frames, &halTimeStamp),
-                                   ignoredErrors);
-    if (retval == Result::OK) {
-        timeStamp->tvSec = halTimeStamp.tv_sec;
-        timeStamp->tvNSec = halTimeStamp.tv_nsec;
-    }
-    return retval;
-}
-
-Return<void> StreamOut::getPresentationPosition(
-    getPresentationPosition_cb _hidl_cb) {
-    uint64_t frames = 0;
-    TimeSpec timeStamp = {0, 0};
-    Result retval = getPresentationPositionImpl(mStream, &frames, &timeStamp);
-    _hidl_cb(retval, frames, timeStamp);
-    return Void();
-}
-
-Return<Result> StreamOut::start() {
-    return mStreamMmap->start();
-}
-
-Return<Result> StreamOut::stop() {
-    return mStreamMmap->stop();
-}
-
-Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames,
-                                         createMmapBuffer_cb _hidl_cb) {
-    return mStreamMmap->createMmapBuffer(
-        minSizeFrames, audio_stream_out_frame_size(mStream), _hidl_cb);
-}
-
-Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {
-    return mStreamMmap->getMmapPosition(_hidl_cb);
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
diff --git a/audio/2.0/default/StreamOut.h b/audio/2.0/default/StreamOut.h
deleted file mode 100644
index 99352bc..0000000
--- a/audio/2.0/default/StreamOut.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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_AUDIO_V2_0_STREAMOUT_H
-#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
-
-#include <atomic>
-#include <memory>
-
-#include <android/hardware/audio/2.0/IStreamOut.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <fmq/EventFlag.h>
-#include <fmq/MessageQueue.h>
-#include <utils/Thread.h>
-
-#include "Device.h"
-#include "Stream.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioChannelMask;
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioFormat;
-using ::android::hardware::audio::V2_0::AudioDrain;
-using ::android::hardware::audio::V2_0::DeviceAddress;
-using ::android::hardware::audio::V2_0::IStream;
-using ::android::hardware::audio::V2_0::IStreamOut;
-using ::android::hardware::audio::V2_0::IStreamOutCallback;
-using ::android::hardware::audio::V2_0::ParameterValue;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::audio::V2_0::TimeSpec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct StreamOut : public IStreamOut {
-    typedef MessageQueue<WriteCommand, kSynchronizedReadWrite> CommandMQ;
-    typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
-    typedef MessageQueue<WriteStatus, kSynchronizedReadWrite> StatusMQ;
-
-    StreamOut(const sp<Device>& device, audio_stream_out_t* stream);
-
-    // Methods from ::android::hardware::audio::V2_0::IStream follow.
-    Return<uint64_t> getFrameSize()  override;
-    Return<uint64_t> getFrameCount()  override;
-    Return<uint64_t> getBufferSize()  override;
-    Return<uint32_t> getSampleRate()  override;
-    Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb)  override;
-    Return<Result> setSampleRate(uint32_t sampleRateHz)  override;
-    Return<AudioChannelMask> getChannelMask()  override;
-    Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb)  override;
-    Return<Result> setChannelMask(AudioChannelMask mask)  override;
-    Return<AudioFormat> getFormat()  override;
-    Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb)  override;
-    Return<Result> setFormat(AudioFormat format)  override;
-    Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb)  override;
-    Return<Result> addEffect(uint64_t effectId)  override;
-    Return<Result> removeEffect(uint64_t effectId)  override;
-    Return<Result> standby()  override;
-    Return<AudioDevice> getDevice()  override;
-    Return<Result> setDevice(const DeviceAddress& address)  override;
-    Return<Result> setConnectedState(const DeviceAddress& address, bool connected)  override;
-    Return<Result> setHwAvSync(uint32_t hwAvSync)  override;
-    Return<void> getParameters(
-            const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb)  override;
-    Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters)  override;
-    Return<void> debugDump(const hidl_handle& fd)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
-    Return<uint32_t> getLatency()  override;
-    Return<Result> setVolume(float left, float right)  override;
-    Return<void> prepareForWriting(
-            uint32_t frameSize, uint32_t framesCount, prepareForWriting_cb _hidl_cb)  override;
-    Return<void> getRenderPosition(getRenderPosition_cb _hidl_cb)  override;
-    Return<void> getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb)  override;
-    Return<Result> setCallback(const sp<IStreamOutCallback>& callback)  override;
-    Return<Result> clearCallback()  override;
-    Return<void> supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb)  override;
-    Return<Result> pause()  override;
-    Return<Result> resume()  override;
-    Return<bool> supportsDrain()  override;
-    Return<Result> drain(AudioDrain type)  override;
-    Return<Result> flush()  override;
-    Return<void> getPresentationPosition(getPresentationPosition_cb _hidl_cb)  override;
-    Return<Result> start() override;
-    Return<Result> stop() override;
-    Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
-    Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
-
-    static Result getPresentationPositionImpl(
-            audio_stream_out_t *stream, uint64_t *frames, TimeSpec *timeStamp);
-
-  private:
-    bool mIsClosed;
-    const sp<Device> mDevice;
-    audio_stream_out_t *mStream;
-    const sp<Stream> mStreamCommon;
-    const sp<StreamMmap<audio_stream_out_t>> mStreamMmap;
-    sp<IStreamOutCallback> mCallback;
-    std::unique_ptr<CommandMQ> mCommandMQ;
-    std::unique_ptr<DataMQ> mDataMQ;
-    std::unique_ptr<StatusMQ> mStatusMQ;
-    EventFlag* mEfGroup;
-    std::atomic<bool> mStopWriteThread;
-    sp<Thread> mWriteThread;
-
-    virtual ~StreamOut();
-
-    static int asyncCallback(stream_callback_event_t event, void *param, void *cookie);
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
diff --git a/audio/2.0/default/Util.h b/audio/2.0/default/Util.h
deleted file mode 100644
index 72eea50..0000000
--- a/audio/2.0/default/Util.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_AUDIO_V2_0_UTIL_H
-#define ANDROID_HARDWARE_AUDIO_V2_0_UTIL_H
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-namespace implementation {
-
-/** @return true if gain is between 0 and 1 included. */
-constexpr bool isGainNormalized(float gain) {
-    return gain >= 0.0 && gain <= 1.0;
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_V2_0_UTIL_H
diff --git a/audio/2.0/default/android.hardware.audio@2.0-service.rc b/audio/2.0/default/android.hardware.audio@2.0-service.rc
index eeaf71b..a76770d 100644
--- a/audio/2.0/default/android.hardware.audio@2.0-service.rc
+++ b/audio/2.0/default/android.hardware.audio@2.0-service.rc
@@ -1,4 +1,4 @@
-service audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service
+service vendor.audio-hal-2-0 /vendor/bin/hw/android.hardware.audio@2.0-service
     class hal
     user audioserver
     # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
diff --git a/audio/2.0/default/service.cpp b/audio/2.0/default/service.cpp
index a215108..3cf7134 100644
--- a/audio/2.0/default/service.cpp
+++ b/audio/2.0/default/service.cpp
@@ -16,11 +16,12 @@
 
 #define LOG_TAG "audiohalservice"
 
-#include <hidl/HidlTransportSupport.h>
-#include <hidl/LegacySupport.h>
 #include <android/hardware/audio/2.0/IDevicesFactory.h>
 #include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
@@ -28,7 +29,8 @@
 
 using android::hardware::audio::effect::V2_0::IEffectsFactory;
 using android::hardware::audio::V2_0::IDevicesFactory;
-using android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
+using V2_0_ISoundTriggerHw = android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
+using V2_1_ISoundTriggerHw = android::hardware::soundtrigger::V2_1::ISoundTriggerHw;
 using android::hardware::registerPassthroughServiceImplementation;
 
 using android::OK;
@@ -41,8 +43,10 @@
     status = registerPassthroughServiceImplementation<IEffectsFactory>();
     LOG_ALWAYS_FATAL_IF(status != OK, "Error while registering audio effects service: %d", status);
     // Soundtrigger might be not present.
-    status = registerPassthroughServiceImplementation<ISoundTriggerHw>();
-    ALOGE_IF(status != OK, "Error while registering soundtrigger service: %d", status);
+    status = registerPassthroughServiceImplementation<V2_1_ISoundTriggerHw>();
+    ALOGW_IF(status != OK, "Registering soundtrigger V2.1 service was unsuccessful: %d", status);
+    status = registerPassthroughServiceImplementation<V2_0_ISoundTriggerHw>();
+    ALOGW_IF(status != OK, "Registering soundtrigger V2.0 service was unsuccessful: %d", status);
     joinRpcThreadpool();
     return status;
 }
diff --git a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
deleted file mode 100644
index fd175de..0000000
--- a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ /dev/null
@@ -1,1369 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "VtsHalAudioV2_0TargetTest"
-
-#include <algorithm>
-#include <cmath>
-#include <cstddef>
-#include <cstdio>
-#include <limits>
-#include <string>
-#include <vector>
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-
-#include <android-base/logging.h>
-
-#include <android/hardware/audio/2.0/IDevice.h>
-#include <android/hardware/audio/2.0/IDevicesFactory.h>
-#include <android/hardware/audio/2.0/IPrimaryDevice.h>
-#include <android/hardware/audio/2.0/types.h>
-#include <android/hardware/audio/common/2.0/types.h>
-
-#include "utility/AssertOk.h"
-#include "utility/Documentation.h"
-#include "utility/EnvironmentTearDown.h"
-#include "utility/PrettyPrintAudioTypes.h"
-#include "utility/ReturnIn.h"
-
-using std::string;
-using std::to_string;
-using std::vector;
-
-using ::android::sp;
-using ::android::hardware::Return;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::MQDescriptorSync;
-using ::android::hardware::audio::V2_0::AudioDrain;
-using ::android::hardware::audio::V2_0::DeviceAddress;
-using ::android::hardware::audio::V2_0::IDevice;
-using ::android::hardware::audio::V2_0::IPrimaryDevice;
-using TtyMode = ::android::hardware::audio::V2_0::IPrimaryDevice::TtyMode;
-using ::android::hardware::audio::V2_0::IDevicesFactory;
-using ::android::hardware::audio::V2_0::IStream;
-using ::android::hardware::audio::V2_0::IStreamIn;
-using ::android::hardware::audio::V2_0::TimeSpec;
-using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters;
-using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus;
-using ::android::hardware::audio::V2_0::IStreamOut;
-using ::android::hardware::audio::V2_0::IStreamOutCallback;
-using ::android::hardware::audio::V2_0::MmapBufferInfo;
-using ::android::hardware::audio::V2_0::MmapPosition;
-using ::android::hardware::audio::V2_0::ParameterValue;
-using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::audio::common::V2_0::AudioChannelMask;
-using ::android::hardware::audio::common::V2_0::AudioConfig;
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioFormat;
-using ::android::hardware::audio::common::V2_0::AudioHandleConsts;
-using ::android::hardware::audio::common::V2_0::AudioInputFlag;
-using ::android::hardware::audio::common::V2_0::AudioIoHandle;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioOffloadInfo;
-using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::common::V2_0::ThreadInfo;
-
-using namespace ::android::hardware::audio::common::test::utility;
-
-// Instance to register global tearDown
-static Environment* environment;
-
-class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   protected:
-    // Convenient member to store results
-    Result res;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-////////////////////// getService audio_devices_factory //////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-// Test all audio devices
-class AudioHidlTest : public HidlTest {
-   public:
-    void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp());  // setup base
-
-        if (devicesFactory == nullptr) {
-            environment->registerTearDown([] { devicesFactory.clear(); });
-            devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<
-                IDevicesFactory>();
-        }
-        ASSERT_TRUE(devicesFactory != nullptr);
-    }
-
-   protected:
-    // Cache the devicesFactory retrieval to speed up each test by ~0.5s
-    static sp<IDevicesFactory> devicesFactory;
-};
-sp<IDevicesFactory> AudioHidlTest::devicesFactory;
-
-TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
-    doc::test("test the getService (called in SetUp)");
-}
-
-TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
-    doc::test("test passing an invalid parameter to openDevice");
-    IDevicesFactory::Result result;
-    sp<IDevice> device;
-    ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device(-1),
-                                         returnIn(result, device)));
-    ASSERT_EQ(IDevicesFactory::Result::INVALID_ARGUMENTS, result);
-    ASSERT_TRUE(device == nullptr);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-/////////////////////////////// openDevice primary ///////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-// Test the primary device
-class AudioPrimaryHidlTest : public AudioHidlTest {
-   public:
-    /** Primary HAL test are NOT thread safe. */
-    void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp());  // setup base
-
-        if (device == nullptr) {
-            IDevicesFactory::Result result;
-            sp<IDevice> baseDevice;
-            ASSERT_OK(
-                devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
-                                           returnIn(result, baseDevice)));
-            ASSERT_OK(result);
-            ASSERT_TRUE(baseDevice != nullptr);
-
-            environment->registerTearDown([] { device.clear(); });
-            device = IPrimaryDevice::castFrom(baseDevice);
-            ASSERT_TRUE(device != nullptr);
-        }
-    }
-
-   protected:
-    // Cache the device opening to speed up each test by ~0.5s
-    static sp<IPrimaryDevice> device;
-};
-sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
-
-TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
-    doc::test("Test the openDevice (called in SetUp)");
-}
-
-TEST_F(AudioPrimaryHidlTest, Init) {
-    doc::test("Test that the audio primary hal initialized correctly");
-    ASSERT_OK(device->initCheck());
-}
-
-//////////////////////////////////////////////////////////////////////////////
-///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-template <class Property>
-class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
-   protected:
-    /** Test a property getter and setter. */
-    template <class Getter, class Setter>
-    void testAccessors(const string& propertyName,
-                       const vector<Property>& valuesToTest, Setter setter,
-                       Getter getter,
-                       const vector<Property>& invalidValues = {}) {
-        Property initialValue;  // Save initial value to restore it at the end
-                                // of the test
-        ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
-        ASSERT_OK(res);
-
-        for (Property setValue : valuesToTest) {
-            SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
-                         testing::PrintToString(setValue));
-            ASSERT_OK((device.get()->*setter)(setValue));
-            Property getValue;
-            // Make sure the getter returns the same value just set
-            ASSERT_OK((device.get()->*getter)(returnIn(res, getValue)));
-            ASSERT_OK(res);
-            EXPECT_EQ(setValue, getValue);
-        }
-
-        for (Property invalidValue : invalidValues) {
-            SCOPED_TRACE("Try to set " + propertyName +
-                         " with the invalid value " +
-                         testing::PrintToString(invalidValue));
-            EXPECT_RESULT(Result::INVALID_ARGUMENTS,
-                          (device.get()->*setter)(invalidValue));
-        }
-
-        ASSERT_OK(
-            (device.get()->*setter)(initialValue));  // restore initial value
-    }
-
-    /** Test the getter and setter of an optional feature. */
-    template <class Getter, class Setter>
-    void testOptionalAccessors(const string& propertyName,
-                               const vector<Property>& valuesToTest,
-                               Setter setter, Getter getter,
-                               const vector<Property>& invalidValues = {}) {
-        doc::test("Test the optional " + propertyName + " getters and setter");
-        {
-            SCOPED_TRACE("Test feature support by calling the getter");
-            Property initialValue;
-            ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
-            if (res == Result::NOT_SUPPORTED) {
-                doc::partialTest(propertyName + " getter is not supported");
-                return;
-            }
-            ASSERT_OK(res);  // If it is supported it must succeed
-        }
-        // The feature is supported, test it
-        testAccessors(propertyName, valuesToTest, setter, getter,
-                      invalidValues);
-    }
-};
-
-using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>;
-
-TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
-    doc::test("Check that the mic can be muted and unmuted");
-    testAccessors("mic mute", {true, false, true}, &IDevice::setMicMute,
-                  &IDevice::getMicMute);
-    // TODO: check that the mic is really muted (all sample are 0)
-}
-
-TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
-    doc::test(
-        "If master mute is supported, try to mute and unmute the master "
-        "output");
-    testOptionalAccessors("master mute", {true, false, true},
-                          &IDevice::setMasterMute, &IDevice::getMasterMute);
-    // TODO: check that the master volume is really muted
-}
-
-using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
-TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
-    doc::test("Test the master volume if supported");
-    testOptionalAccessors("master volume", {0, 0.5, 1},
-                          &IDevice::setMasterVolume, &IDevice::getMasterVolume,
-                          {-0.1, 1.1, NAN, INFINITY, -INFINITY,
-                           1 + std::numeric_limits<float>::epsilon()});
-    // TODO: check that the master volume is really changed
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//////////////////////////////// AudioPatches ////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
-   protected:
-    bool areAudioPatchesSupported() {
-        auto result = device->supportsAudioPatches();
-        EXPECT_IS_OK(result);
-        return result;
-    }
-};
-
-TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
-    doc::test("Test if audio patches are supported");
-    if (!areAudioPatchesSupported()) {
-        doc::partialTest("Audio patches are not supported");
-        return;
-    }
-    // TODO: test audio patches
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//////////////// Required and recommended audio format support ///////////////
-// From:
-// https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording
-// From:
-// https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback
-/////////// TODO: move to the beginning of the file for easier update ////////
-//////////////////////////////////////////////////////////////////////////////
-
-class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
-   public:
-    // Cache result ?
-    static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
-        return combineAudioConfig(
-            {AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
-            {8000, 11025, 16000, 22050, 32000, 44100},
-            {AudioFormat::PCM_16_BIT});
-    }
-
-    static const vector<AudioConfig>
-    getRecommendedSupportPlaybackAudioConfig() {
-        return combineAudioConfig(
-            {AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
-            {24000, 48000}, {AudioFormat::PCM_16_BIT});
-    }
-
-    static const vector<AudioConfig> getSupportedPlaybackAudioConfig() {
-        // TODO: retrieve audio config supported by the platform
-        // as declared in the policy configuration
-        return {};
-    }
-
-    static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
-        return combineAudioConfig({AudioChannelMask::IN_MONO},
-                                  {8000, 11025, 16000, 44100},
-                                  {AudioFormat::PCM_16_BIT});
-    }
-    static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
-        return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000},
-                                  {AudioFormat::PCM_16_BIT});
-    }
-    static const vector<AudioConfig> getSupportedCaptureAudioConfig() {
-        // TODO: retrieve audio config supported by the platform
-        // as declared in the policy configuration
-        return {};
-    }
-
-   private:
-    static const vector<AudioConfig> combineAudioConfig(
-        vector<AudioChannelMask> channelMasks, vector<uint32_t> sampleRates,
-        vector<AudioFormat> formats) {
-        vector<AudioConfig> configs;
-        for (auto channelMask : channelMasks) {
-            for (auto sampleRate : sampleRates) {
-                for (auto format : formats) {
-                    AudioConfig config{};
-                    // leave offloadInfo to 0
-                    config.channelMask = channelMask;
-                    config.sampleRateHz = sampleRate;
-                    config.format = format;
-                    // FIXME: leave frameCount to 0 ?
-                    configs.push_back(config);
-                }
-            }
-        }
-        return configs;
-    }
-};
-
-/** Generate a test name based on an audio config.
- *
- * As the only parameter changing are channel mask and sample rate,
- * only print those ones in the test name.
- */
-static string generateTestName(
-    const testing::TestParamInfo<AudioConfig>& info) {
-    const AudioConfig& config = info.param;
-    return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" +
-           // "MONO" is more clear than "FRONT_LEFT"
-           ((config.channelMask == AudioChannelMask::OUT_MONO ||
-             config.channelMask == AudioChannelMask::IN_MONO)
-                ? "MONO"
-                : toString(config.channelMask));
-}
-
-//////////////////////////////////////////////////////////////////////////////
-///////////////////////////// getInputBufferSize /////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-// FIXME: execute input test only if platform declares
-// android.hardware.microphone
-//        how to get this value ? is it a property ???
-
-class AudioCaptureConfigPrimaryTest
-    : public AudioConfigPrimaryTest,
-      public ::testing::WithParamInterface<AudioConfig> {
-   protected:
-    void inputBufferSizeTest(const AudioConfig& audioConfig,
-                             bool supportRequired) {
-        uint64_t bufferSize;
-        ASSERT_OK(
-            device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
-
-        switch (res) {
-            case Result::INVALID_ARGUMENTS:
-                EXPECT_FALSE(supportRequired);
-                break;
-            case Result::OK:
-                // Check that the buffer is of a sane size
-                // For now only that it is > 0
-                EXPECT_GT(bufferSize, uint64_t(0));
-                break;
-            default:
-                FAIL() << "Invalid return status: "
-                       << ::testing::PrintToString(res);
-        }
-    }
-};
-
-// Test that the required capture config and those declared in the policy are
-// indeed supported
-class RequiredInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
-TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) {
-    doc::test(
-        "Input buffer size must be retrievable for a format with required "
-        "support.");
-    inputBufferSizeTest(GetParam(), true);
-}
-INSTANTIATE_TEST_CASE_P(
-    RequiredInputBufferSize, RequiredInputBufferSizeTest,
-    ::testing::ValuesIn(
-        AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
-    &generateTestName);
-INSTANTIATE_TEST_CASE_P(
-    SupportedInputBufferSize, RequiredInputBufferSizeTest,
-    ::testing::ValuesIn(
-        AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
-    &generateTestName);
-
-// Test that the recommended capture config are supported or lead to a
-// INVALID_ARGUMENTS return
-class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
-TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) {
-    doc::test(
-        "Input buffer size should be retrievable for a format with recommended "
-        "support.");
-    inputBufferSizeTest(GetParam(), false);
-}
-INSTANTIATE_TEST_CASE_P(
-    RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
-    ::testing::ValuesIn(
-        AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
-    &generateTestName);
-
-//////////////////////////////////////////////////////////////////////////////
-/////////////////////////////// setScreenState ///////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-TEST_F(AudioPrimaryHidlTest, setScreenState) {
-    doc::test("Check that the hal can receive the screen state");
-    for (bool turnedOn : {false, true, true, false, false}) {
-        auto ret = device->setScreenState(turnedOn);
-        ASSERT_IS_OK(ret);
-        Result result = ret;
-        auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
-        ASSERT_RESULT(okOrNotSupported, result);
-    }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//////////////////////////// {get,set}Parameters /////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-TEST_F(AudioPrimaryHidlTest, getParameters) {
-    doc::test("Check that the hal can set and get parameters");
-    hidl_vec<hidl_string> keys;
-    hidl_vec<ParameterValue> values;
-    ASSERT_OK(device->getParameters(keys, returnIn(res, values)));
-    ASSERT_OK(device->setParameters(values));
-    values.resize(0);
-    ASSERT_OK(device->setParameters(values));
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//////////////////////////////// debugDebug //////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-template <class DebugDump>
-static void testDebugDump(DebugDump debugDump) {
-    // File descriptors to our pipe. fds[0] corresponds to the read end and
-    // fds[1] to the write end.
-    int fds[2];
-    ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
-
-    // Make sure that the pipe is at least 1 MB in size. The test process runs
-    // in su domain, so it should be safe to make this call.
-    fcntl(fds[0], F_SETPIPE_SZ, 1 << 20);
-
-    // Wrap the temporary file file descriptor in a native handle
-    auto* nativeHandle = native_handle_create(1, 0);
-    ASSERT_NE(nullptr, nativeHandle);
-    nativeHandle->data[0] = fds[1];
-
-    // Wrap this native handle in a hidl handle
-    hidl_handle handle;
-    handle.setTo(nativeHandle, false /*take ownership*/);
-
-    ASSERT_OK(debugDump(handle));
-
-    // Check that at least one bit was written by the hal
-    // TODO: debugDump does not return a Result.
-    // This mean that the hal can not report that it not implementing the
-    // function.
-    char buff;
-    if (read(fds[0], &buff, 1) != 1) {
-        doc::note("debugDump does not seem implemented");
-    }
-    EXPECT_EQ(0, close(fds[0])) << errno;
-    EXPECT_EQ(0, close(fds[1])) << errno;
-}
-
-TEST_F(AudioPrimaryHidlTest, DebugDump) {
-    doc::test("Check that the hal can dump its state without error");
-    testDebugDump([](const auto& handle) { return device->debugDump(handle); });
-}
-
-TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
-    doc::test("Check that the hal dump doesn't crash on invalid arguments");
-    ASSERT_OK(device->debugDump(hidl_handle()));
-}
-
-//////////////////////////////////////////////////////////////////////////////
-////////////////////////// open{Output,Input}Stream //////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-template <class Stream>
-class OpenStreamTest : public AudioConfigPrimaryTest,
-                       public ::testing::WithParamInterface<AudioConfig> {
-   protected:
-    template <class Open>
-    void testOpen(Open openStream, const AudioConfig& config) {
-        // FIXME: Open a stream without an IOHandle
-        //        This is not required to be accepted by hal implementations
-        AudioIoHandle ioHandle =
-            (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
-        AudioConfig suggestedConfig{};
-        ASSERT_OK(openStream(ioHandle, config,
-                             returnIn(res, stream, suggestedConfig)));
-
-        // TODO: only allow failure for RecommendedPlaybackAudioConfig
-        switch (res) {
-            case Result::OK:
-                ASSERT_TRUE(stream != nullptr);
-                audioConfig = config;
-                break;
-            case Result::INVALID_ARGUMENTS:
-                ASSERT_TRUE(stream == nullptr);
-                AudioConfig suggestedConfigRetry;
-                // Could not open stream with config, try again with the
-                // suggested one
-                ASSERT_OK(
-                    openStream(ioHandle, suggestedConfig,
-                               returnIn(res, stream, suggestedConfigRetry)));
-                // This time it must succeed
-                ASSERT_OK(res);
-                ASSERT_TRUE(stream != nullptr);
-                audioConfig = suggestedConfig;
-                break;
-            default:
-                FAIL() << "Invalid return status: "
-                       << ::testing::PrintToString(res);
-        }
-        open = true;
-    }
-
-    Return<Result> closeStream() {
-        open = false;
-        return stream->close();
-    }
-
-   private:
-    void TearDown() override {
-        if (open) {
-            ASSERT_OK(stream->close());
-        }
-    }
-
-   protected:
-    AudioConfig audioConfig;
-    DeviceAddress address = {};
-    sp<Stream> stream;
-    bool open = false;
-};
-
-////////////////////////////// openOutputStream //////////////////////////////
-
-class OutputStreamTest : public OpenStreamTest<IStreamOut> {
-    virtual void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
-        address.device = AudioDevice::OUT_DEFAULT;
-        const AudioConfig& config = GetParam();
-        AudioOutputFlag flags =
-            AudioOutputFlag::NONE;  // TODO: test all flag combination
-        testOpen(
-            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
-                return device->openOutputStream(handle, address, config, flags,
-                                                cb);
-            },
-            config);
-    }
-};
-TEST_P(OutputStreamTest, OpenOutputStreamTest) {
-    doc::test(
-        "Check that output streams can be open with the required and "
-        "recommended config");
-    // Open done in SetUp
-}
-INSTANTIATE_TEST_CASE_P(
-    RequiredOutputStreamConfigSupport, OutputStreamTest,
-    ::testing::ValuesIn(
-        AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
-    &generateTestName);
-INSTANTIATE_TEST_CASE_P(
-    SupportedOutputStreamConfig, OutputStreamTest,
-    ::testing::ValuesIn(
-        AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
-    &generateTestName);
-
-INSTANTIATE_TEST_CASE_P(
-    RecommendedOutputStreamConfigSupport, OutputStreamTest,
-    ::testing::ValuesIn(
-        AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
-    &generateTestName);
-
-////////////////////////////// openInputStream //////////////////////////////
-
-class InputStreamTest : public OpenStreamTest<IStreamIn> {
-    virtual void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
-        address.device = AudioDevice::IN_DEFAULT;
-        const AudioConfig& config = GetParam();
-        AudioInputFlag flags =
-            AudioInputFlag::NONE;  // TODO: test all flag combination
-        AudioSource source =
-            AudioSource::DEFAULT;  // TODO: test all flag combination
-        testOpen(
-            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
-                return device->openInputStream(handle, address, config, flags,
-                                               source, cb);
-            },
-            config);
-    }
-};
-
-TEST_P(InputStreamTest, OpenInputStreamTest) {
-    doc::test(
-        "Check that input streams can be open with the required and "
-        "recommended config");
-    // Open done in setup
-}
-INSTANTIATE_TEST_CASE_P(
-    RequiredInputStreamConfigSupport, InputStreamTest,
-    ::testing::ValuesIn(
-        AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
-    &generateTestName);
-INSTANTIATE_TEST_CASE_P(
-    SupportedInputStreamConfig, InputStreamTest,
-    ::testing::ValuesIn(
-        AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
-    &generateTestName);
-
-INSTANTIATE_TEST_CASE_P(
-    RecommendedInputStreamConfigSupport, InputStreamTest,
-    ::testing::ValuesIn(
-        AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
-    &generateTestName);
-
-//////////////////////////////////////////////////////////////////////////////
-////////////////////////////// IStream getters ///////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-/** Unpack the provided result.
- * If the result is not OK, register a failure and return an undefined value. */
-template <class R>
-static R extract(Return<R> ret) {
-    if (!ret.isOk()) {
-        EXPECT_IS_OK(ret);
-        return R{};
-    }
-    return ret;
-}
-
-/* Could not find a way to write a test for two parametrized class fixure
- * thus use this macro do duplicate tests for Input and Output stream */
-#define TEST_IO_STREAM(test_name, documentation, code) \
-    TEST_P(InputStreamTest, test_name) {               \
-        doc::test(documentation);                      \
-        code;                                          \
-    }                                                  \
-    TEST_P(OutputStreamTest, test_name) {              \
-        doc::test(documentation);                      \
-        code;                                          \
-    }
-
-TEST_IO_STREAM(
-    GetFrameCount,
-    "Check that the stream frame count == the one it was opened with",
-    ASSERT_EQ(audioConfig.frameCount, extract(stream->getFrameCount())))
-
-TEST_IO_STREAM(GetSampleRate, "Check that the stream sample rate == the one it was opened with",
-               ASSERT_EQ(audioConfig.sampleRateHz, extract(stream->getSampleRate())))
-
-TEST_IO_STREAM(GetChannelMask, "Check that the stream channel mask == the one it was opened with",
-               ASSERT_EQ(audioConfig.channelMask, extract(stream->getChannelMask())))
-
-TEST_IO_STREAM(GetFormat,
-               "Check that the stream format == the one it was opened with",
-               ASSERT_EQ(audioConfig.format, extract(stream->getFormat())))
-
-// TODO: for now only check that the framesize is not incoherent
-TEST_IO_STREAM(GetFrameSize,
-               "Check that the stream frame size == the one it was opened with",
-               ASSERT_GT(extract(stream->getFrameSize()), 0U))
-
-TEST_IO_STREAM(GetBufferSize,
-               "Check that the stream buffer size== the one it was opened with",
-               ASSERT_GE(extract(stream->getBufferSize()),
-                         extract(stream->getFrameSize())));
-
-template <class Property, class CapabilityGetter>
-static void testCapabilityGetter(const string& name, IStream* stream,
-                                 CapabilityGetter capablityGetter,
-                                 Return<Property> (IStream::*getter)(),
-                                 Return<Result> (IStream::*setter)(Property),
-                                 bool currentMustBeSupported = true) {
-    hidl_vec<Property> capabilities;
-    ASSERT_OK((stream->*capablityGetter)(returnIn(capabilities)));
-    if (capabilities.size() == 0) {
-        // The default hal should probably return a NOT_SUPPORTED if the hal
-        // does not expose
-        // capability retrieval. For now it returns an empty list if not
-        // implemented
-        doc::partialTest(name + " is not supported");
-        return;
-    };
-
-    if (currentMustBeSupported) {
-        Property currentValue = extract((stream->*getter)());
-        EXPECT_NE(std::find(capabilities.begin(), capabilities.end(), currentValue),
-                  capabilities.end())
-            << "current " << name << " is not in the list of the supported ones "
-            << toString(capabilities);
-    }
-
-    // Check that all declared supported values are indeed supported
-    for (auto capability : capabilities) {
-        auto ret = (stream->*setter)(capability);
-        ASSERT_TRUE(ret.isOk());
-        if (ret == Result::NOT_SUPPORTED) {
-            doc::partialTest("Setter is not supported");
-            return;
-        }
-        ASSERT_OK(ret);
-        ASSERT_EQ(capability, extract((stream->*getter)()));
-    }
-}
-
-TEST_IO_STREAM(SupportedSampleRate,
-               "Check that the stream sample rate is declared as supported",
-               testCapabilityGetter("getSupportedSampleRate", stream.get(),
-                                    &IStream::getSupportedSampleRates,
-                                    &IStream::getSampleRate,
-                                    &IStream::setSampleRate,
-                                    // getSupportedSampleRate returns the native sampling rates,
-                                    // (the sampling rates that can be played without resampling)
-                                    // but other sampling rates can be supported by the HAL.
-                                    false))
-
-TEST_IO_STREAM(SupportedChannelMask,
-               "Check that the stream channel mask is declared as supported",
-               testCapabilityGetter("getSupportedChannelMask", stream.get(),
-                                    &IStream::getSupportedChannelMasks,
-                                    &IStream::getChannelMask,
-                                    &IStream::setChannelMask))
-
-TEST_IO_STREAM(SupportedFormat,
-               "Check that the stream format is declared as supported",
-               testCapabilityGetter("getSupportedFormat", stream.get(),
-                                    &IStream::getSupportedFormats,
-                                    &IStream::getFormat, &IStream::setFormat))
-
-static void testGetDevice(IStream* stream, AudioDevice expectedDevice) {
-    // Unfortunately the interface does not allow the implementation to return
-    // NOT_SUPPORTED
-    // Thus allow NONE as signaling that the call is not supported.
-    auto ret = stream->getDevice();
-    ASSERT_IS_OK(ret);
-    AudioDevice device = ret;
-    ASSERT_TRUE(device == expectedDevice || device == AudioDevice::NONE)
-        << "Expected: " << ::testing::PrintToString(expectedDevice)
-        << "\n  Actual: " << ::testing::PrintToString(device);
-}
-
-TEST_IO_STREAM(GetDevice,
-               "Check that the stream device == the one it was opened with",
-               areAudioPatchesSupported()
-                   ? doc::partialTest("Audio patches are supported")
-                   : testGetDevice(stream.get(), address.device))
-
-static void testSetDevice(IStream* stream, const DeviceAddress& address) {
-    DeviceAddress otherAddress = address;
-    otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0
-                              ? AudioDevice::OUT_SPEAKER
-                              : AudioDevice::IN_BUILTIN_MIC;
-    EXPECT_OK(stream->setDevice(otherAddress));
-
-    ASSERT_OK(stream->setDevice(address));  // Go back to the original value
-}
-
-TEST_IO_STREAM(
-    SetDevice,
-    "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC",
-    areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported")
-                               : testSetDevice(stream.get(), address))
-
-static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
-    uint32_t sampleRateHz;
-    AudioChannelMask mask;
-    AudioFormat format;
-
-    stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
-
-    // FIXME: the qcom hal it does not currently negotiate the sampleRate &
-    // channel mask
-    EXPECT_EQ(expectedConfig.sampleRateHz, sampleRateHz);
-    EXPECT_EQ(expectedConfig.channelMask, mask);
-    EXPECT_EQ(expectedConfig.format, format);
-}
-
-TEST_IO_STREAM(GetAudioProperties,
-               "Check that the stream audio properties == the ones it was opened with",
-               testGetAudioProperties(stream.get(), audioConfig))
-
-static void testConnectedState(IStream* stream) {
-    DeviceAddress address = {};
-    using AD = AudioDevice;
-    for (auto device :
-         {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
-        address.device = device;
-
-        ASSERT_OK(stream->setConnectedState(address, true));
-        ASSERT_OK(stream->setConnectedState(address, false));
-    }
-}
-TEST_IO_STREAM(SetConnectedState,
-               "Check that the stream can be notified of device connection and "
-               "deconnection",
-               testConnectedState(stream.get()))
-
-static auto invalidArgsOrNotSupportedOrOK = {Result::INVALID_ARGUMENTS,
-                                             Result::NOT_SUPPORTED, Result::OK};
-TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value",
-               ASSERT_RESULT(invalidArgsOrNotSupportedOrOK,
-                             stream->setHwAvSync(666)))
-
-TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail",
-               ASSERT_IS_OK(device->getHwAvSync()));
-
-static void checkGetNoParameter(IStream* stream, hidl_vec<hidl_string> keys,
-                                vector<Result> expectedResults) {
-    hidl_vec<ParameterValue> parameters;
-    Result res;
-    ASSERT_OK(stream->getParameters(keys, returnIn(res, parameters)));
-    ASSERT_RESULT(expectedResults, res);
-    if (res == Result::OK) {
-        for (auto& parameter : parameters) {
-            ASSERT_EQ(0U, parameter.value.size()) << toString(parameter);
-        }
-    }
-}
-
-/* Get/Set parameter is intended to be an opaque channel between vendors app and
- * their HALs.
- * Thus can not be meaningfully tested.
- */
-TEST_IO_STREAM(getEmptySetParameter, "Retrieve the values of an empty set",
-               checkGetNoParameter(stream.get(), {} /* keys */, {Result::OK}))
-
-TEST_IO_STREAM(getNonExistingParameter,
-               "Retrieve the values of an non existing parameter",
-               checkGetNoParameter(stream.get(),
-                                   {"Non existing key"} /* keys */,
-                                   {Result::NOT_SUPPORTED}))
-
-TEST_IO_STREAM(setEmptySetParameter,
-               "Set the values of an empty set of parameters",
-               ASSERT_RESULT(Result::OK, stream->setParameters({})))
-
-TEST_IO_STREAM(
-    setNonExistingParameter, "Set the values of an non existing parameter",
-    // Unfortunately, the set_parameter legacy interface did not return any
-    // error code when a key is not supported.
-    // To allow implementation to just wrapped the legacy one, consider OK as a
-    // valid result for setting a non existing parameter.
-    ASSERT_RESULT(invalidArgsOrNotSupportedOrOK,
-                  stream->setParameters({{"non existing key", "0"}})))
-
-TEST_IO_STREAM(DebugDump,
-               "Check that a stream can dump its state without error",
-               testDebugDump([this](const auto& handle) {
-                   return stream->debugDump(handle);
-               }))
-
-TEST_IO_STREAM(DebugDumpInvalidArguments,
-               "Check that the stream dump doesn't crash on invalid arguments",
-               ASSERT_OK(stream->debugDump(hidl_handle())))
-
-//////////////////////////////////////////////////////////////////////////////
-////////////////////////////// addRemoveEffect ///////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-TEST_IO_STREAM(AddNonExistingEffect, "Adding a non existing effect should fail",
-               ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->addEffect(666)))
-TEST_IO_STREAM(RemoveNonExistingEffect,
-               "Removing a non existing effect should fail",
-               ASSERT_RESULT(Result::INVALID_ARGUMENTS,
-                             stream->removeEffect(666)))
-
-// TODO: positive tests
-
-//////////////////////////////////////////////////////////////////////////////
-/////////////////////////////// Control ////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-TEST_IO_STREAM(standby, "Make sure the stream can be put in stanby",
-               ASSERT_OK(stream->standby()))  // can not fail
-
-static vector<Result> invalidStateOrNotSupported = {Result::INVALID_STATE,
-                                                    Result::NOT_SUPPORTED};
-
-TEST_IO_STREAM(startNoMmap,
-               "Starting a mmaped stream before mapping it should fail",
-               ASSERT_RESULT(invalidStateOrNotSupported, stream->start()))
-
-TEST_IO_STREAM(stopNoMmap,
-               "Stopping a mmaped stream before mapping it should fail",
-               ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
-
-TEST_IO_STREAM(getMmapPositionNoMmap,
-               "Get a stream Mmap position before mapping it should fail",
-               ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
-
-TEST_IO_STREAM(close, "Make sure a stream can be closed",
-               ASSERT_OK(closeStream()))
-TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice",
-               ASSERT_OK(closeStream());
-               ASSERT_RESULT(Result::INVALID_STATE, closeStream()))
-
-static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS,
-                                         Result::NOT_SUPPORTED};
-static void testCreateTooBigMmapBuffer(IStream* stream) {
-    MmapBufferInfo info;
-    Result res;
-    // Assume that int max is a value too big to be allocated
-    // This is true currently with a 32bit media server, but might not when it
-    // will run in 64 bit
-    auto minSizeFrames = std::numeric_limits<int32_t>::max();
-    ASSERT_OK(stream->createMmapBuffer(minSizeFrames, returnIn(res, info)));
-    ASSERT_RESULT(invalidArgsOrNotSupported, res);
-}
-
-TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer too big should fail",
-               testCreateTooBigMmapBuffer(stream.get()))
-
-static void testGetMmapPositionOfNonMmapedStream(IStream* stream) {
-    Result res;
-    MmapPosition position;
-    ASSERT_OK(stream->getMmapPosition(returnIn(res, position)));
-    ASSERT_RESULT(invalidArgsOrNotSupported, res);
-}
-
-TEST_IO_STREAM(
-    GetMmapPositionOfNonMmapedStream,
-    "Retrieving the mmap position of a non mmaped stream should fail",
-    testGetMmapPositionOfNonMmapedStream(stream.get()))
-
-//////////////////////////////////////////////////////////////////////////////
-///////////////////////////////// StreamIn ///////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-TEST_P(InputStreamTest, GetAudioSource) {
-    doc::test(
-        "Retrieving the audio source of an input stream should always succeed");
-    AudioSource source;
-    ASSERT_OK(stream->getAudioSource(returnIn(res, source)));
-    if (res == Result::NOT_SUPPORTED) {
-        doc::partialTest("getAudioSource is not supported");
-        return;
-    }
-    ASSERT_OK(res);
-    ASSERT_EQ(AudioSource::DEFAULT, source);
-}
-
-static void testUnitaryGain(std::function<Return<Result>(float)> setGain) {
-    for (float value :
-         (float[]){-INFINITY, -1.0, 1.0 + std::numeric_limits<float>::epsilon(),
-                   2.0, INFINITY, NAN}) {
-        EXPECT_RESULT(Result::INVALID_ARGUMENTS, setGain(value)) << "value="
-                                                                 << value;
-    }
-    // Do not consider -0.0 as an invalid value as it is == with 0.0
-    for (float value : {-0.0, 0.0, 0.01, 0.5, 0.09, 1.0 /* Restore volume*/}) {
-        EXPECT_OK(setGain(value)) << "value=" << value;
-    }
-}
-
-static void testOptionalUnitaryGain(
-    std::function<Return<Result>(float)> setGain, string debugName) {
-    auto result = setGain(1);
-    ASSERT_IS_OK(result);
-    if (result == Result::NOT_SUPPORTED) {
-        doc::partialTest(debugName + " is not supported");
-        return;
-    }
-    testUnitaryGain(setGain);
-}
-
-TEST_P(InputStreamTest, SetGain) {
-    doc::test("The gain of an input stream should only be set between [0,1]");
-    testOptionalUnitaryGain(
-        [this](float volume) { return stream->setGain(volume); },
-        "InputStream::setGain");
-}
-
-static void testPrepareForReading(IStreamIn* stream, uint32_t frameSize,
-                                  uint32_t framesCount) {
-    Result res;
-    // Ignore output parameters as the call should fail
-    ASSERT_OK(stream->prepareForReading(
-        frameSize, framesCount,
-        [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
-    EXPECT_RESULT(Result::INVALID_ARGUMENTS, res);
-}
-
-TEST_P(InputStreamTest, PrepareForReadingWithZeroBuffer) {
-    doc::test(
-        "Preparing a stream for reading with a 0 sized buffer should fail");
-    testPrepareForReading(stream.get(), 0, 0);
-}
-
-TEST_P(InputStreamTest, PrepareForReadingWithHugeBuffer) {
-    doc::test(
-        "Preparing a stream for reading with a 2^32 sized buffer should fail");
-    testPrepareForReading(stream.get(), 1,
-                          std::numeric_limits<uint32_t>::max());
-}
-
-TEST_P(InputStreamTest, PrepareForReadingCheckOverflow) {
-    doc::test(
-        "Preparing a stream for reading with a overflowing sized buffer should "
-        "fail");
-    auto uintMax = std::numeric_limits<uint32_t>::max();
-    testPrepareForReading(stream.get(), uintMax, uintMax);
-}
-
-TEST_P(InputStreamTest, GetInputFramesLost) {
-    doc::test(
-        "The number of frames lost on a never started stream should be 0");
-    auto ret = stream->getInputFramesLost();
-    ASSERT_IS_OK(ret);
-    uint32_t framesLost{ret};
-    ASSERT_EQ(0U, framesLost);
-}
-
-TEST_P(InputStreamTest, getCapturePosition) {
-    doc::test(
-        "The capture position of a non prepared stream should not be "
-        "retrievable");
-    uint64_t frames;
-    uint64_t time;
-    ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, time)));
-    ASSERT_RESULT(invalidStateOrNotSupported, res);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-///////////////////////////////// StreamIn ///////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-TEST_P(OutputStreamTest, getLatency) {
-    doc::test("Make sure latency is over 0");
-    auto result = stream->getLatency();
-    ASSERT_IS_OK(result);
-    ASSERT_GT(result, 0U);
-}
-
-TEST_P(OutputStreamTest, setVolume) {
-    doc::test("Try to set the output volume");
-    testOptionalUnitaryGain(
-        [this](float volume) { return stream->setVolume(volume, volume); },
-        "setVolume");
-}
-
-static void testPrepareForWriting(IStreamOut* stream, uint32_t frameSize,
-                                  uint32_t framesCount) {
-    Result res;
-    // Ignore output parameters as the call should fail
-    ASSERT_OK(stream->prepareForWriting(
-        frameSize, framesCount,
-        [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
-    EXPECT_RESULT(Result::INVALID_ARGUMENTS, res);
-}
-
-TEST_P(OutputStreamTest, PrepareForWriteWithZeroBuffer) {
-    doc::test(
-        "Preparing a stream for writing with a 0 sized buffer should fail");
-    testPrepareForWriting(stream.get(), 0, 0);
-}
-
-TEST_P(OutputStreamTest, PrepareForWriteWithHugeBuffer) {
-    doc::test(
-        "Preparing a stream for writing with a 2^32 sized buffer should fail");
-    testPrepareForWriting(stream.get(), 1,
-                          std::numeric_limits<uint32_t>::max());
-}
-
-TEST_P(OutputStreamTest, PrepareForWritingCheckOverflow) {
-    doc::test(
-        "Preparing a stream for writing with a overflowing sized buffer should "
-        "fail");
-    auto uintMax = std::numeric_limits<uint32_t>::max();
-    testPrepareForWriting(stream.get(), uintMax, uintMax);
-}
-
-struct Capability {
-    Capability(IStreamOut* stream) {
-        EXPECT_OK(stream->supportsPauseAndResume(returnIn(pause, resume)));
-        auto ret = stream->supportsDrain();
-        EXPECT_IS_OK(ret);
-        if (ret.isOk()) {
-            drain = ret;
-        }
-    }
-    bool pause = false;
-    bool resume = false;
-    bool drain = false;
-};
-
-TEST_P(OutputStreamTest, SupportsPauseAndResumeAndDrain) {
-    doc::test(
-        "Implementation must expose pause, resume and drain capabilities");
-    Capability(stream.get());
-}
-
-template <class Value>
-static void checkInvalidStateOr0(Result res, Value value) {
-    switch (res) {
-        case Result::INVALID_STATE:
-            break;
-        case Result::OK:
-            ASSERT_EQ(0U, value);
-            break;
-        default:
-            FAIL() << "Unexpected result " << toString(res);
-    }
-}
-
-TEST_P(OutputStreamTest, GetRenderPosition) {
-    doc::test("A new stream render position should be 0 or INVALID_STATE");
-    uint32_t dspFrames;
-    ASSERT_OK(stream->getRenderPosition(returnIn(res, dspFrames)));
-    if (res == Result::NOT_SUPPORTED) {
-        doc::partialTest("getRenderPosition is not supported");
-        return;
-    }
-    checkInvalidStateOr0(res, dspFrames);
-}
-
-TEST_P(OutputStreamTest, GetNextWriteTimestamp) {
-    doc::test("A new stream next write timestamp should be 0 or INVALID_STATE");
-    uint64_t timestampUs;
-    ASSERT_OK(stream->getNextWriteTimestamp(returnIn(res, timestampUs)));
-    if (res == Result::NOT_SUPPORTED) {
-        doc::partialTest("getNextWriteTimestamp is not supported");
-        return;
-    }
-    checkInvalidStateOr0(res, timestampUs);
-}
-
-/** Stub implementation of out stream callback. */
-class MockOutCallbacks : public IStreamOutCallback {
-    Return<void> onWriteReady() override { return {}; }
-    Return<void> onDrainReady() override { return {}; }
-    Return<void> onError() override { return {}; }
-};
-
-static bool isAsyncModeSupported(IStreamOut* stream) {
-    auto res = stream->setCallback(new MockOutCallbacks);
-    stream->clearCallback();  // try to restore the no callback state, ignore
-                              // any error
-    auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
-    EXPECT_RESULT(okOrNotSupported, res);
-    return res.isOk() ? res == Result::OK : false;
-}
-
-TEST_P(OutputStreamTest, SetCallback) {
-    doc::test(
-        "If supported, registering callback for async operation should never "
-        "fail");
-    if (!isAsyncModeSupported(stream.get())) {
-        doc::partialTest("The stream does not support async operations");
-        return;
-    }
-    ASSERT_OK(stream->setCallback(new MockOutCallbacks));
-    ASSERT_OK(stream->setCallback(new MockOutCallbacks));
-}
-
-TEST_P(OutputStreamTest, clearCallback) {
-    doc::test(
-        "If supported, clearing a callback to go back to sync operation should "
-        "not fail");
-    if (!isAsyncModeSupported(stream.get())) {
-        doc::partialTest("The stream does not support async operations");
-        return;
-    }
-    // TODO: Clarify if clearing a non existing callback should fail
-    ASSERT_OK(stream->setCallback(new MockOutCallbacks));
-    ASSERT_OK(stream->clearCallback());
-}
-
-TEST_P(OutputStreamTest, Resume) {
-    doc::test(
-        "If supported, a stream should fail to resume if not previously "
-        "paused");
-    if (!Capability(stream.get()).resume) {
-        doc::partialTest("The output stream does not support resume");
-        return;
-    }
-    ASSERT_RESULT(Result::INVALID_STATE, stream->resume());
-}
-
-TEST_P(OutputStreamTest, Pause) {
-    doc::test(
-        "If supported, a stream should fail to pause if not previously "
-        "started");
-    if (!Capability(stream.get()).pause) {
-        doc::partialTest("The output stream does not support pause");
-        return;
-    }
-    ASSERT_RESULT(Result::INVALID_STATE, stream->resume());
-}
-
-static void testDrain(IStreamOut* stream, AudioDrain type) {
-    if (!Capability(stream).drain) {
-        doc::partialTest("The output stream does not support drain");
-        return;
-    }
-    ASSERT_RESULT(Result::OK, stream->drain(type));
-}
-
-TEST_P(OutputStreamTest, DrainAll) {
-    doc::test("If supported, a stream should always succeed to drain");
-    testDrain(stream.get(), AudioDrain::ALL);
-}
-
-TEST_P(OutputStreamTest, DrainEarlyNotify) {
-    doc::test("If supported, a stream should always succeed to drain");
-    testDrain(stream.get(), AudioDrain::EARLY_NOTIFY);
-}
-
-TEST_P(OutputStreamTest, FlushStop) {
-    doc::test("If supported, a stream should always succeed to flush");
-    auto ret = stream->flush();
-    ASSERT_IS_OK(ret);
-    if (ret == Result::NOT_SUPPORTED) {
-        doc::partialTest("Flush is not supported");
-        return;
-    }
-    ASSERT_OK(ret);
-}
-
-TEST_P(OutputStreamTest, GetPresentationPositionStop) {
-    doc::test(
-        "If supported, a stream should always succeed to retrieve the "
-        "presentation position");
-    uint64_t frames;
-    TimeSpec mesureTS;
-    ASSERT_OK(stream->getPresentationPosition(returnIn(res, frames, mesureTS)));
-    if (res == Result::NOT_SUPPORTED) {
-        doc::partialTest("getpresentationPosition is not supported");
-        return;
-    }
-    ASSERT_EQ(0U, frames);
-
-    if (mesureTS.tvNSec == 0 && mesureTS.tvSec == 0) {
-        // As the stream has never written a frame yet,
-        // the timestamp does not really have a meaning, allow to return 0
-        return;
-    }
-
-    // Make sure the return measure is not more than 1s old.
-    struct timespec currentTS;
-    ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &currentTS)) << errno;
-
-    auto toMicroSec = [](uint64_t sec, auto nsec) {
-        return sec * 1e+6 + nsec / 1e+3;
-    };
-    auto currentTime = toMicroSec(currentTS.tv_sec, currentTS.tv_nsec);
-    auto mesureTime = toMicroSec(mesureTS.tvSec, mesureTS.tvNSec);
-    ASSERT_PRED2([](auto c, auto m) { return c - m < 1e+6; }, currentTime,
-                 mesureTime);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-/////////////////////////////// PrimaryDevice ////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
-    doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
-    testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); });
-}
-
-TEST_F(AudioPrimaryHidlTest, setMode) {
-    doc::test(
-        "Make sure setMode always succeeds if mode is valid "
-        "and fails otherwise");
-    // Test Invalid values
-    for (AudioMode mode :
-         {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) {
-        SCOPED_TRACE("mode=" + toString(mode));
-        ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode));
-    }
-    // Test valid values
-    for (AudioMode mode :
-         {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
-          AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
-        SCOPED_TRACE("mode=" + toString(mode));
-        ASSERT_OK(device->setMode(mode));
-    }
-}
-
-TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
-    doc::test("Query and set the BT SCO NR&EC state");
-    testOptionalAccessors("BtScoNrecEnabled", {true, false, true},
-                          &IPrimaryDevice::setBtScoNrecEnabled,
-                          &IPrimaryDevice::getBtScoNrecEnabled);
-}
-
-TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
-    doc::test("Query and set the SCO whideband state");
-    testOptionalAccessors("BtScoWideband", {true, false, true},
-                          &IPrimaryDevice::setBtScoWidebandEnabled,
-                          &IPrimaryDevice::getBtScoWidebandEnabled);
-}
-
-using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<TtyMode>;
-TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
-    doc::test("Query and set the TTY mode state");
-    testOptionalAccessors(
-        "TTY mode", {TtyMode::OFF, TtyMode::HCO, TtyMode::VCO, TtyMode::FULL},
-        &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
-}
-
-TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
-    doc::test("Query and set the HAC state");
-    testOptionalAccessors("HAC", {true, false, true},
-                          &IPrimaryDevice::setHacEnabled,
-                          &IPrimaryDevice::getHacEnabled);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//////////////////// Clean caches on global tear down ////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-int main(int argc, char** argv) {
-    environment = new Environment;
-    ::testing::AddGlobalTestEnvironment(environment);
-    ::testing::InitGoogleTest(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    return status;
-}
diff --git a/audio/2.0/vts/functional/ValidateAudioConfiguration.cpp b/audio/2.0/vts/functional/ValidateAudioConfiguration.cpp
deleted file mode 100644
index ec3259a..0000000
--- a/audio/2.0/vts/functional/ValidateAudioConfiguration.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string>
-#include <unistd.h>
-
-#include "utility/ValidateXml.h"
-
-TEST(CheckConfig, audioPolicyConfigurationValidation) {
-    const char* configName = "audio_policy_configuration.xml";
-    const char* possibleConfigLocations[] = {"/odm/etc", "/vendor/etc", "/system/etc"};
-    const char* configSchemaPath = "/data/local/tmp/audio_policy_configuration.xsd";
-
-    for (std::string folder : possibleConfigLocations) {
-        const auto configPath = folder + '/' + configName;
-        if (access(configPath.c_str(), R_OK) == 0) {
-            ASSERT_VALID_XML(configPath.c_str(), configSchemaPath);
-            return; // The framework does not read past the first config file found
-        }
-    }
-}
diff --git a/audio/4.0/Android.bp b/audio/4.0/Android.bp
new file mode 100644
index 0000000..6e217d9
--- /dev/null
+++ b/audio/4.0/Android.bp
@@ -0,0 +1,48 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio@4.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IDevice.hal",
+        "IDevicesFactory.hal",
+        "IPrimaryDevice.hal",
+        "IStream.hal",
+        "IStreamIn.hal",
+        "IStreamOut.hal",
+        "IStreamOutCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@4.0",
+        "android.hardware.audio.effect@4.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "AudioDrain",
+        "AudioFrequencyResponsePoint",
+        "AudioMicrophoneChannelMapping",
+        "AudioMicrophoneCoordinate",
+        "AudioMicrophoneDirectionality",
+        "AudioMicrophoneLocation",
+        "DeviceAddress",
+        "MessageQueueFlagBits",
+        "MicrophoneInfo",
+        "MmapBufferFlag",
+        "MmapBufferInfo",
+        "MmapPosition",
+        "ParameterValue",
+        "PlaybackTrackMetadata",
+        "RecordTrackMetadata",
+        "Result",
+        "SinkMetadata",
+        "SourceMetadata",
+        "TimeSpec",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
+
diff --git a/audio/4.0/IDevice.hal b/audio/4.0/IDevice.hal
new file mode 100644
index 0000000..bb58568
--- /dev/null
+++ b/audio/4.0/IDevice.hal
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.0;
+import IStreamIn;
+import IStreamOut;
+
+interface IDevice {
+    /**
+     * Returns whether the audio hardware interface has been initialized.
+     *
+     * @return retval OK on success, NOT_INITIALIZED on failure.
+     */
+    initCheck() generates (Result retval);
+
+    /**
+     * Sets the audio volume for all audio activities other than voice call. If
+     * NOT_SUPPORTED is returned, the software mixer will emulate this
+     * capability.
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setMasterVolume(float volume) generates (Result retval);
+
+    /**
+     * Get the current master volume value for the HAL, if the HAL supports
+     * master volume control. For example, AudioFlinger will query this value
+     * from the primary audio HAL when the service starts and use the value for
+     * setting the initial master volume across all HALs. HALs which do not
+     * support this method must return NOT_SUPPORTED in 'retval'.
+     *
+     * @return retval operation completion status.
+     * @return volume 1.0f means unity, 0.0f is zero.
+     */
+    getMasterVolume() generates (Result retval, float volume);
+
+    /**
+     * Sets microphone muting state.
+     *
+     * @param mute whether microphone is muted.
+     * @return retval operation completion status.
+     */
+    setMicMute(bool mute) generates (Result retval);
+
+    /**
+     * Gets whether microphone is muted.
+     *
+     * @return retval operation completion status.
+     * @return mute whether microphone is muted.
+     */
+    getMicMute() generates (Result retval, bool mute);
+
+    /**
+     * Set the audio mute status for all audio activities. If the return value
+     * is NOT_SUPPORTED, the software mixer will emulate this capability.
+     *
+     * @param mute whether audio is muted.
+     * @return retval operation completion status.
+     */
+    setMasterMute(bool mute) generates (Result retval);
+
+    /**
+     * Get the current master mute status for the HAL, if the HAL supports
+     * master mute control. AudioFlinger will query this value from the primary
+     * audio HAL when the service starts and use the value for setting the
+     * initial master mute across all HALs. HAL must indicate that the feature
+     * is not supported by returning NOT_SUPPORTED status.
+     *
+     * @return retval operation completion status.
+     * @return mute whether audio is muted.
+     */
+    getMasterMute() generates (Result retval, bool mute);
+
+    /**
+     * Returns audio input buffer size according to parameters passed or
+     * INVALID_ARGUMENTS if one of the parameters is not supported.
+     *
+     * @param config audio configuration.
+     * @return retval operation completion status.
+     * @return bufferSize input buffer size in bytes.
+     */
+    getInputBufferSize(AudioConfig config)
+            generates (Result retval, uint64_t bufferSize);
+
+    /**
+     * This method creates and opens the audio hardware output stream.
+     * If the stream can not be opened with the proposed audio config,
+     * HAL must provide suggested values for the audio config.
+     *
+     * @param ioHandle handle assigned by AudioFlinger.
+     * @param device device type and (if needed) address.
+     * @param config stream configuration.
+     * @param flags additional flags.
+     * @param sourceMetadata Description of the audio that will be played.
+                             May be used by implementations to configure hardware effects.
+     * @return retval operation completion status.
+     * @return outStream created output stream.
+     * @return suggestedConfig in case of invalid parameters, suggested config.
+     */
+    openOutputStream(
+            AudioIoHandle ioHandle,
+            DeviceAddress device,
+            AudioConfig config,
+            bitfield<AudioOutputFlag> flags,
+            SourceMetadata sourceMetadata) generates (
+                    Result retval,
+                    IStreamOut outStream,
+                    AudioConfig suggestedConfig);
+
+    /**
+     * This method creates and opens the audio hardware input stream.
+     * If the stream can not be opened with the proposed audio config,
+     * HAL must provide suggested values for the audio config.
+     *
+     * @param ioHandle handle assigned by AudioFlinger.
+     * @param device device type and (if needed) address.
+     * @param config stream configuration.
+     * @param flags additional flags.
+     * @param source source specification.
+     * @param sinkMetadata Description of the audio that is suggested by the client.
+     *                     May be used by implementations to configure hardware effects.
+     * @return retval operation completion status.
+     * @return inStream in case of success, created input stream.
+     * @return suggestedConfig in case of invalid parameters, suggested config.
+     */
+    openInputStream(
+            AudioIoHandle ioHandle,
+            DeviceAddress device,
+            AudioConfig config,
+            bitfield<AudioInputFlag> flags,
+            SinkMetadata sinkMetadata) generates (
+                    Result retval,
+                    IStreamIn inStream,
+                    AudioConfig suggestedConfig);
+
+    /**
+     * Returns whether HAL supports audio patches.
+     *
+     * @return supports true if audio patches are supported.
+     */
+    supportsAudioPatches() generates (bool supports);
+
+    /**
+     * Creates an audio patch between several source and sink ports.  The handle
+     * is allocated by the HAL and must be unique for this audio HAL module.
+     *
+     * @param sources patch sources.
+     * @param sinks patch sinks.
+     * @return retval operation completion status.
+     * @return patch created patch handle.
+     */
+    createAudioPatch(vec<AudioPortConfig> sources, vec<AudioPortConfig> sinks)
+            generates (Result retval, AudioPatchHandle patch);
+
+    /**
+     * Release an audio patch.
+     *
+     * @param patch patch handle.
+     * @return retval operation completion status.
+     */
+    releaseAudioPatch(AudioPatchHandle patch) generates (Result retval);
+
+    /**
+     * Returns the list of supported attributes for a given audio port.
+     *
+     * As input, 'port' contains the information (type, role, address etc...)
+     * needed by the HAL to identify the port.
+     *
+     * As output, 'resultPort' contains possible attributes (sampling rates,
+     * formats, channel masks, gain controllers...) for this port.
+     *
+     * @param port port identifier.
+     * @return retval operation completion status.
+     * @return resultPort port descriptor with all parameters filled up.
+     */
+    getAudioPort(AudioPort port)
+            generates (Result retval, AudioPort resultPort);
+
+    /**
+     * Set audio port configuration.
+     *
+     * @param config audio port configuration.
+     * @return retval operation completion status.
+     */
+    setAudioPortConfig(AudioPortConfig config) generates (Result retval);
+
+    /**
+     * Gets the HW synchronization source of the device. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_HW_AV_SYNC on the legacy HAL.
+     * Optional method
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     * @return hwAvSync HW synchronization source
+     */
+    getHwAvSync() generates (Result retval, AudioHwSync hwAvSync);
+
+    /**
+     * Sets whether the screen is on. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_KEY_SCREEN_STATE on the legacy HAL.
+     * Optional method
+     *
+     * @param turnedOn whether the screen is turned on.
+     * @return retval operation completion status.
+     */
+    setScreenState(bool turnedOn) generates (Result retval);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be retrieved at the same time.
+     * The implementation should return as many requested parameters
+     * as possible, even if one or more is not supported
+     *
+     * @param context provides more information about the request
+     * @param keys keys of the requested parameters
+     * @return retval operation completion status.
+     *         OK must be returned if keys is empty.
+     *         NOT_SUPPORTED must be returned if at least one key is unknown.
+     * @return parameters parameter key value pairs.
+     *         Must contain the value of all requested keys if retval == OK
+     */
+    getParameters(vec<ParameterValue> context, vec<string> keys)
+            generates (Result retval, vec<ParameterValue> parameters);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be set at the same time though this is
+     * discouraged as it make failure analysis harder.
+     *
+     * If possible, a failed setParameters should not impact the platform state.
+     *
+     * @param context provides more information about the request
+     * @param parameters parameter key value pairs.
+     * @return retval operation completion status.
+     *         All parameters must be successfully set for OK to be returned
+     */
+    setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+            generates (Result retval);
+
+    /**
+     * Returns an array with available microphones in device.
+     *
+     * @return retval INVALID_STATE if the call is not successful,
+     *                OK otherwise.
+     *
+     * @return microphones array with microphones info
+     */
+    getMicrophones()
+         generates(Result retval, vec<MicrophoneInfo> microphones);
+};
diff --git a/audio/4.0/IDevicesFactory.hal b/audio/4.0/IDevicesFactory.hal
new file mode 100644
index 0000000..c552c6d
--- /dev/null
+++ b/audio/4.0/IDevicesFactory.hal
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.0;
+import IDevice;
+
+interface IDevicesFactory {
+    /** Allows a HAL implementation to be split in multiple independent
+     *  devices (called module in the pre-treble API).
+     *  Note that this division is arbitrary and implementation are free
+     *  to only have a Primary.
+     *  The framework will query the devices according to audio_policy_configuration.xml
+     *
+     *  Each Device value is interchangeable with any other and the framework
+     *  does not differentiate between values with the following exceptions:
+     *  - the Primary device must always be present
+     *  - the R_SUBMIX that is used to forward audio of REMOTE_SUBMIX DEVICES
+     */
+    enum Device : int32_t {
+        PRIMARY,
+        A2DP,
+        USB,
+        R_SUBMIX,
+        STUB,
+        CODEC_OFFLOAD,
+        SECONDARY,
+        AUXILIARY,
+        /** Multi Stream Decoder */
+        MSD
+    };
+
+    /**
+     * Opens an audio device. To close the device, it is necessary to release
+     * references to the returned device object.
+     *
+     * @param device device type.
+     * @return retval operation completion status. Returns INVALID_ARGUMENTS
+     *         if there is no corresponding hardware module found,
+     *         NOT_INITIALIZED if an error occured while opening the hardware
+     *         module.
+     * @return result the interface for the created device.
+     */
+    openDevice(Device device) generates (Result retval, IDevice result);
+};
diff --git a/audio/4.0/IPrimaryDevice.hal b/audio/4.0/IPrimaryDevice.hal
new file mode 100644
index 0000000..f3d904c
--- /dev/null
+++ b/audio/4.0/IPrimaryDevice.hal
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.0;
+import IDevice;
+
+interface IPrimaryDevice extends IDevice {
+    /**
+     * Sets the audio volume of a voice call.
+     *
+     * @param volume 1.0f means unity, 0.0f is zero.
+     * @return retval operation completion status.
+     */
+    setVoiceVolume(float volume) generates (Result retval);
+
+    /**
+     * This method is used to notify the HAL about audio mode changes.
+     *
+     * @param mode new mode.
+     * @return retval operation completion status.
+     */
+    setMode(AudioMode mode) generates (Result retval);
+
+    /**
+     * Gets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+     * Calling this method is equivalent to getting AUDIO_PARAMETER_KEY_BT_NREC
+     * on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT SCO NR + EC are enabled.
+     */
+    getBtScoNrecEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT SCO Noise Reduction and Echo Cancellation are enabled.
+     * Calling this method is equivalent to setting AUDIO_PARAMETER_KEY_BT_NREC
+     * on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT SCO NR + EC are enabled.
+     * @return retval operation completion status.
+     */
+    setBtScoNrecEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Gets whether BT SCO Wideband mode is enabled. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether BT Wideband is enabled.
+     */
+    getBtScoWidebandEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether BT SCO Wideband mode is enabled. Calling this method is
+     * equivalent to setting AUDIO_PARAMETER_KEY_BT_SCO_WB on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether BT Wideband is enabled.
+     * @return retval operation completion status.
+     */
+    setBtScoWidebandEnabled(bool enabled) generates (Result retval);
+
+    enum TtyMode : int32_t {
+        OFF,
+        VCO,
+        HCO,
+        FULL
+    };
+
+    /**
+     * Gets current TTY mode selection. Calling this method is equivalent to
+     * getting AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return mode TTY mode.
+     */
+    getTtyMode() generates (Result retval, TtyMode mode);
+
+    /**
+     * Sets current TTY mode. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_KEY_TTY_MODE on the legacy HAL.
+     *
+     * @param mode TTY mode.
+     * @return retval operation completion status.
+     */
+    setTtyMode(TtyMode mode) generates (Result retval);
+
+    /**
+     * Gets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+     * enabled. Calling this method is equivalent to getting
+     * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+     *
+     * @return retval operation completion status.
+     * @return enabled whether HAC mode is enabled.
+     */
+    getHacEnabled() generates (Result retval, bool enabled);
+
+    /**
+     * Sets whether Hearing Aid Compatibility - Telecoil (HAC-T) mode is
+     * enabled. Calling this method is equivalent to setting
+     * AUDIO_PARAMETER_KEY_HAC on the legacy HAL.
+     * Optional method
+     *
+     * @param enabled whether HAC mode is enabled.
+     * @return retval operation completion status.
+     */
+    setHacEnabled(bool enabled) generates (Result retval);
+};
diff --git a/audio/4.0/IStream.hal b/audio/4.0/IStream.hal
new file mode 100644
index 0000000..f05d7b0
--- /dev/null
+++ b/audio/4.0/IStream.hal
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.0;
+import android.hardware.audio.effect@4.0::IEffect;
+
+interface IStream {
+    /**
+     * Return the frame size (number of bytes per sample).
+     *
+     * @return frameSize frame size in bytes.
+     */
+    getFrameSize() generates (uint64_t frameSize);
+
+    /**
+     * Return the frame count of the buffer. Calling this method is equivalent
+     * to getting AUDIO_PARAMETER_STREAM_FRAME_COUNT on the legacy HAL.
+     *
+     * @return count frame count.
+     */
+    getFrameCount() generates (uint64_t count);
+
+    /**
+     * Return the size of input/output buffer in bytes for this stream.
+     * It must be a multiple of the frame size.
+     *
+     * @return buffer buffer size in bytes.
+     */
+    getBufferSize() generates (uint64_t bufferSize);
+
+    /**
+     * Return the sampling rate in Hz.
+     *
+     * @return sampleRateHz sample rate in Hz.
+     */
+    getSampleRate() generates (uint32_t sampleRateHz);
+
+    /**
+     * Return supported native sampling rates of the stream for a given format.
+     * A supported native sample rate is a sample rate that can be efficiently
+     * played by the hardware (typically without sample-rate conversions).
+     *
+     * This function is only called for dynamic profile. If called for
+     * non-dynamic profile is should return NOT_SUPPORTED or the same list
+     * as in audio_policy_configuration.xml.
+     *
+     * Calling this method is equivalent to getting
+     * AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES on the legacy HAL.
+     *
+     *
+     * @param format audio format for which the sample rates are supported.
+     * @return retval operation completion status.
+     *                Must be OK if the format is supported.
+     * @return sampleRateHz supported sample rates.
+     */
+    getSupportedSampleRates(AudioFormat format)
+            generates (Result retval, vec<uint32_t> sampleRates);
+
+    /**
+     * Sets the sampling rate of the stream. Calling this method is equivalent
+     * to setting AUDIO_PARAMETER_STREAM_SAMPLING_RATE on the legacy HAL.
+     * Optional method. If implemented, only called on a stopped stream.
+     *
+     * @param sampleRateHz sample rate in Hz.
+     * @return retval operation completion status.
+     */
+    setSampleRate(uint32_t sampleRateHz) generates (Result retval);
+
+    /**
+     * Return the channel mask of the stream.
+     *
+     * @return mask channel mask.
+     */
+    getChannelMask() generates (bitfield<AudioChannelMask> mask);
+
+    /**
+     * Return supported channel masks of the stream. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_CHANNELS on the legacy
+     * HAL.
+     *
+     * @param format audio format for which the channel masks are supported.
+     * @return retval operation completion status.
+     *                Must be OK if the format is supported.
+     * @return masks supported audio masks.
+     */
+    getSupportedChannelMasks(AudioFormat format)
+            generates (Result retval, vec<bitfield<AudioChannelMask>> masks);
+
+    /**
+     * Sets the channel mask of the stream. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_STREAM_CHANNELS on the legacy HAL.
+     * Optional method
+     *
+     * @param format audio format.
+     * @return retval operation completion status.
+     */
+    setChannelMask(bitfield<AudioChannelMask> mask) generates (Result retval);
+
+    /**
+     * Return the audio format of the stream.
+     *
+     * @return format audio format.
+     */
+    getFormat() generates (AudioFormat format);
+
+    /**
+     * Return supported audio formats of the stream. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_STREAM_SUP_FORMATS on the legacy
+     * HAL.
+     *
+     * @return formats supported audio formats.
+     */
+    getSupportedFormats() generates (vec<AudioFormat> formats);
+
+    /**
+     * Sets the audio format of the stream. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_STREAM_FORMAT on the legacy HAL.
+     * Optional method
+     *
+     * @param format audio format.
+     * @return retval operation completion status.
+     */
+    setFormat(AudioFormat format) generates (Result retval);
+
+    /**
+     * Convenience method for retrieving several stream parameters in
+     * one transaction.
+     *
+     * @return sampleRateHz sample rate in Hz.
+     * @return mask channel mask.
+     * @return format audio format.
+     */
+    getAudioProperties() generates (
+            uint32_t sampleRateHz, bitfield<AudioChannelMask> mask, AudioFormat format);
+
+    /**
+     * Applies audio effect to the stream.
+     *
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect to apply.
+     * @return retval operation completion status.
+     */
+    addEffect(uint64_t effectId) generates (Result retval);
+
+    /**
+     * Stops application of the effect to the stream.
+     *
+     * @param effectId effect ID (obtained from IEffectsFactory.createEffect) of
+     *                 the effect to remove.
+     * @return retval operation completion status.
+     */
+    removeEffect(uint64_t effectId) generates (Result retval);
+
+    /**
+     * Put the audio hardware input/output into standby mode.
+     * Driver must exit from standby mode at the next I/O operation.
+     *
+     * @return retval operation completion status.
+     */
+    standby() generates (Result retval);
+
+    /**
+     * Return the set of device(s) which this stream is connected to.
+     * Optional method
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     * @return device set of device(s) which this stream is connected to.
+     */
+    getDevice() generates (Result retval, bitfield<AudioDevice> device);
+
+    /**
+     * Connects the stream to the device.
+     *
+     * This method must only be used for HALs that do not support
+     * 'IDevice.createAudioPatch' method. Calling this method is
+     * equivalent to setting AUDIO_PARAMETER_STREAM_ROUTING in the legacy HAL
+     * interface.
+     *
+     * @param address device to connect the stream to.
+     * @return retval operation completion status.
+     */
+    setDevice(DeviceAddress address) generates (Result retval);
+
+    /**
+     * Notifies the stream about device connection state. Calling this method is
+     * equivalent to setting AUDIO_PARAMETER_DEVICE_[DIS]CONNECT on the legacy
+     * HAL.
+     *
+     * @param address audio device specification.
+     * @param connected whether the device is connected.
+     * @return retval operation completion status.
+     */
+    setConnectedState(DeviceAddress address, bool connected)
+            generates (Result retval);
+
+    /**
+     * Sets the HW synchronization source. Calling this method is equivalent to
+     * setting AUDIO_PARAMETER_STREAM_HW_AV_SYNC on the legacy HAL.
+     * Optional method
+     *
+     * @param hwAvSync HW synchronization source
+     * @return retval operation completion status.
+     */
+    setHwAvSync(AudioHwSync hwAvSync) generates (Result retval);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be retrieved at the same time.
+     * The implementation should return as many requested parameters
+     * as possible, even if one or more is not supported
+     *
+     * @param context provides more information about the request
+     * @param keys keys of the requested parameters
+     * @return retval operation completion status.
+     *         OK must be returned if keys is empty.
+     *         NOT_SUPPORTED must be returned if at least one key is unknown.
+     * @return parameters parameter key value pairs.
+     *         Must contain the value of all requested keys if retval == OK
+     */
+    getParameters(vec<ParameterValue> context, vec<string> keys)
+            generates (Result retval, vec<ParameterValue> parameters);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Multiple parameters can be set at the same time though this is
+     * discouraged as it make failure analysis harder.
+     *
+     * If possible, a failed setParameters should not impact the platform state.
+     *
+     * @param context provides more information about the request
+     * @param parameters parameter key value pairs.
+     * @return retval operation completion status.
+     *         All parameters must be successfully set for OK to be returned
+     */
+    setParameters(vec<ParameterValue> context, vec<ParameterValue> parameters)
+            generates (Result retval);
+
+    /**
+     * Called by the framework to start a stream operating in mmap mode.
+     * createMmapBuffer() must be called before calling start().
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     */
+    start() generates (Result retval);
+
+    /**
+     * Called by the framework to stop a stream operating in mmap mode.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the succes.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     */
+    stop() generates (Result retval) ;
+
+    /**
+     * Called by the framework to retrieve information on the mmap buffer used for audio
+     * samples transfer.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @param minSizeFrames minimum buffer size requested. The actual buffer
+     *                     size returned in struct MmapBufferInfo can be larger.
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                NOT_INITIALIZED in case of memory allocation error
+     *                INVALID_ARGUMENTS if the requested buffer size is too large
+     *                INVALID_STATE if called out of sequence
+     * @return info    a MmapBufferInfo struct containing information on the MMMAP buffer created.
+     */
+    createMmapBuffer(int32_t minSizeFrames)
+            generates (Result retval, MmapBufferInfo info);
+
+    /**
+     * Called by the framework to read current read/write position in the mmap buffer
+     * with associated time stamp.
+     * Function only implemented by streams operating in mmap mode.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED on non mmap mode streams
+     *                INVALID_STATE if called out of sequence
+     * @return position a MmapPosition struct containing current HW read/write position in frames
+     *                  with associated time stamp.
+     */
+    getMmapPosition()
+            generates (Result retval, MmapPosition position);
+
+    /**
+     * Called by the framework to deinitialize the stream and free up
+     * all the currently allocated resources. It is recommended to close
+     * the stream on the client side as soon as it is becomes unused.
+     *
+     * @return retval OK in case the success.
+     *                NOT_SUPPORTED if called on IStream instead of input or
+     *                              output stream interface.
+     *                INVALID_STATE if the stream was already closed.
+     */
+    close() generates (Result retval);
+};
diff --git a/audio/4.0/IStreamIn.hal b/audio/4.0/IStreamIn.hal
new file mode 100644
index 0000000..247e826
--- /dev/null
+++ b/audio/4.0/IStreamIn.hal
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.0;
+import IStream;
+
+interface IStreamIn extends IStream {
+    /**
+     * Returns the source descriptor of the input stream. Calling this method is
+     * equivalent to getting AUDIO_PARAMETER_STREAM_INPUT_SOURCE on the legacy
+     * HAL.
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return source audio source.
+     */
+    getAudioSource() generates (Result retval, AudioSource source);
+
+    /**
+     * Set the input gain for the audio driver.
+     * Optional method
+     *
+     * @param gain 1.0f is unity, 0.0f is zero.
+     * @result retval operation completion status.
+     */
+    setGain(float gain) generates (Result retval);
+
+    /**
+     * Commands that can be executed on the driver reader thread.
+     */
+    enum ReadCommand : int32_t {
+        READ,
+        GET_CAPTURE_POSITION
+    };
+
+    /**
+     * Data structure passed to the driver for executing commands
+     * on the driver reader thread.
+     */
+    struct ReadParameters {
+        ReadCommand command;  // discriminator
+        union Params {
+            uint64_t read;    // READ command, amount of bytes to read, >= 0.
+            // No parameters for GET_CAPTURE_POSITION.
+        } params;
+    };
+
+    /**
+     * Data structure passed back to the client via status message queue
+     * of 'read' operation.
+     *
+     * Possible values of 'retval' field:
+     *  - OK, read operation was successful;
+     *  - INVALID_ARGUMENTS, stream was not configured properly;
+     *  - INVALID_STATE, stream is in a state that doesn't allow reads.
+     */
+    struct ReadStatus {
+        Result retval;
+        ReadCommand replyTo;  // discriminator
+        union Reply {
+            uint64_t read;    // READ command, amount of bytes read, >= 0.
+            struct CapturePosition { // same as generated by getCapturePosition.
+                uint64_t frames;
+                uint64_t time;
+            } capturePosition;
+        } reply;
+    };
+
+    /**
+     * Called when the metadata of the stream's sink has been changed.
+     * @param sinkMetadata Description of the audio that is suggested by the clients.
+     */
+    updateSinkMetadata(SinkMetadata sinkMetadata);
+
+    /**
+     * Set up required transports for receiving audio buffers from the driver.
+     *
+     * The transport consists of three message queues:
+     *  -- command queue is used to instruct the reader thread what operation
+     *     to perform;
+     *  -- data queue is used for passing audio data from the driver
+     *     to the client;
+     *  -- status queue is used for reporting operation status
+     *     (e.g. amount of bytes actually read or error code).
+     *
+     * The driver operates on a dedicated thread. The client must ensure that
+     * the thread is given an appropriate priority and assigned to correct
+     * scheduler and cgroup. For this purpose, the method returns identifiers
+     * of the driver thread.
+     *
+     * @param frameSize the size of a single frame, in bytes.
+     * @param framesCount the number of frames in a buffer.
+     * @param threadPriority priority of the driver thread.
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queues.
+     * @return commandMQ a message queue used for passing commands.
+     * @return dataMQ a message queue used for passing audio data in the format
+     *                specified at the stream opening.
+     * @return statusMQ a message queue used for passing status from the driver
+     *                  using ReadStatus structures.
+     * @return threadInfo identifiers of the driver's dedicated thread.
+     */
+    prepareForReading(uint32_t frameSize, uint32_t framesCount)
+    generates (
+            Result retval,
+            fmq_sync<ReadParameters> commandMQ,
+            fmq_sync<uint8_t> dataMQ,
+            fmq_sync<ReadStatus> statusMQ,
+            ThreadInfo threadInfo);
+
+    /**
+     * Return the amount of input frames lost in the audio driver since the last
+     * call of this function.
+     *
+     * Audio driver is expected to reset the value to 0 and restart counting
+     * upon returning the current value by this function call. Such loss
+     * typically occurs when the user space process is blocked longer than the
+     * capacity of audio driver buffers.
+     *
+     * @return framesLost the number of input audio frames lost.
+     */
+    getInputFramesLost() generates (uint32_t framesLost);
+
+    /**
+     * Return a recent count of the number of audio frames received and the
+     * clock time associated with that frame count.
+     *
+     * @return retval INVALID_STATE if the device is not ready/available,
+     *                NOT_SUPPORTED if the command is not supported,
+     *                OK otherwise.
+     * @return frames the total frame count received. This must be as early in
+     *                the capture pipeline as possible. In general, frames
+     *                must be non-negative and must not go "backwards".
+     * @return time is the clock monotonic time when frames was measured. In
+     *              general, time must be a positive quantity and must not
+     *              go "backwards".
+     */
+    getCapturePosition()
+            generates (Result retval, uint64_t frames, uint64_t time);
+
+    /**
+     * Returns an array with active microphones in the stream.
+     *
+     * @return retval INVALID_STATE if the call is not successful,
+     *                OK otherwise.
+     *
+     * @return microphones array with microphones info
+     */
+    getActiveMicrophones()
+               generates(Result retval, vec<MicrophoneInfo> microphones);
+};
diff --git a/audio/4.0/IStreamOut.hal b/audio/4.0/IStreamOut.hal
new file mode 100644
index 0000000..3aa93fc
--- /dev/null
+++ b/audio/4.0/IStreamOut.hal
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.0;
+import IStream;
+import IStreamOutCallback;
+
+interface IStreamOut extends IStream {
+    /**
+     * Return the audio hardware driver estimated latency in milliseconds.
+     *
+     * @return latencyMs latency in milliseconds.
+     */
+    getLatency() generates (uint32_t latencyMs);
+
+    /**
+     * This method is used in situations where audio mixing is done in the
+     * hardware. This method serves as a direct interface with hardware,
+     * allowing to directly set the volume as apposed to via the framework.
+     * This method might produce multiple PCM outputs or hardware accelerated
+     * codecs, such as MP3 or AAC.
+     * Optional method
+     *
+     * @param left left channel attenuation, 1.0f is unity, 0.0f is zero.
+     * @param right right channel attenuation, 1.0f is unity, 0.0f is zero.
+     * @return retval operation completion status.
+     *        If a volume is outside [0,1], return INVALID_ARGUMENTS
+     */
+    setVolume(float left, float right) generates (Result retval);
+
+    /**
+     * Commands that can be executed on the driver writer thread.
+     */
+    enum WriteCommand : int32_t {
+        WRITE,
+        GET_PRESENTATION_POSITION,
+        GET_LATENCY
+    };
+
+    /**
+     * Data structure passed back to the client via status message queue
+     * of 'write' operation.
+     *
+     * Possible values of 'retval' field:
+     *  - OK, write operation was successful;
+     *  - INVALID_ARGUMENTS, stream was not configured properly;
+     *  - INVALID_STATE, stream is in a state that doesn't allow writes;
+     *  - INVALID_OPERATION, retrieving presentation position isn't supported.
+     */
+    struct WriteStatus {
+        Result retval;
+        WriteCommand replyTo;  // discriminator
+        union Reply {
+            uint64_t written;  // WRITE command, amount of bytes written, >= 0.
+            struct PresentationPosition {  // same as generated by
+                uint64_t frames;           // getPresentationPosition.
+                TimeSpec timeStamp;
+            } presentationPosition;
+            uint32_t latencyMs; // Same as generated by getLatency.
+        } reply;
+    };
+
+    /**
+     * Called when the metadata of the stream's source has been changed.
+     * @param sourceMetadata Description of the audio that is played by the clients.
+     */
+    updateSourceMetadata(SourceMetadata sourceMetadata);
+
+    /**
+     * Set up required transports for passing audio buffers to the driver.
+     *
+     * The transport consists of three message queues:
+     *  -- command queue is used to instruct the writer thread what operation
+     *     to perform;
+     *  -- data queue is used for passing audio data from the client
+     *     to the driver;
+     *  -- status queue is used for reporting operation status
+     *     (e.g. amount of bytes actually written or error code).
+     *
+     * The driver operates on a dedicated thread. The client must ensure that
+     * the thread is given an appropriate priority and assigned to correct
+     * scheduler and cgroup. For this purpose, the method returns identifiers
+     * of the driver thread.
+     *
+     * @param frameSize the size of a single frame, in bytes.
+     * @param framesCount the number of frames in a buffer.
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queues.
+     * @return commandMQ a message queue used for passing commands.
+     * @return dataMQ a message queue used for passing audio data in the format
+     *                specified at the stream opening.
+     * @return statusMQ a message queue used for passing status from the driver
+     *                  using WriteStatus structures.
+     * @return threadInfo identifiers of the driver's dedicated thread.
+     */
+    prepareForWriting(uint32_t frameSize, uint32_t framesCount)
+    generates (
+            Result retval,
+            fmq_sync<WriteCommand> commandMQ,
+            fmq_sync<uint8_t> dataMQ,
+            fmq_sync<WriteStatus> statusMQ,
+            ThreadInfo threadInfo);
+
+    /**
+     * Return the number of audio frames written by the audio DSP to DAC since
+     * the output has exited standby.
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return dspFrames number of audio frames written.
+     */
+    getRenderPosition() generates (Result retval, uint32_t dspFrames);
+
+    /**
+     * Get the local time at which the next write to the audio driver will be
+     * presented. The units are microseconds, where the epoch is decided by the
+     * local audio HAL.
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return timestampUs time of the next write.
+     */
+    getNextWriteTimestamp() generates (Result retval, int64_t timestampUs);
+
+    /**
+     * Set the callback interface for notifying completion of non-blocking
+     * write and drain.
+     *
+     * Calling this function implies that all future 'write' and 'drain'
+     * must be non-blocking and use the callback to signal completion.
+     *
+     * 'clearCallback' method needs to be called in order to release the local
+     * callback proxy on the server side and thus dereference the callback
+     * implementation on the client side.
+     *
+     * @return retval operation completion status.
+     */
+    setCallback(IStreamOutCallback callback) generates (Result retval);
+
+    /**
+     * Clears the callback previously set via 'setCallback' method.
+     *
+     * Warning: failure to call this method results in callback implementation
+     * on the client side being held until the HAL server termination.
+     *
+     * If no callback was previously set, the method should be a no-op
+     * and return OK.
+     *
+     * @return retval operation completion status: OK or NOT_SUPPORTED.
+     */
+    clearCallback() generates (Result retval);
+
+    /**
+     * Returns whether HAL supports pausing and resuming of streams.
+     *
+     * @return supportsPause true if pausing is supported.
+     * @return supportsResume true if resume is supported.
+     */
+    supportsPauseAndResume()
+            generates (bool supportsPause, bool supportsResume);
+
+    /**
+     * Notifies to the audio driver to stop playback however the queued buffers
+     * are retained by the hardware. Useful for implementing pause/resume. Empty
+     * implementation if not supported however must be implemented for hardware
+     * with non-trivial latency. In the pause state, some audio hardware may
+     * still be using power. Client code may consider calling 'suspend' after a
+     * timeout to prevent that excess power usage.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    pause() generates (Result retval);
+
+    /**
+     * Notifies to the audio driver to resume playback following a pause.
+     * Returns error INVALID_STATE if called without matching pause.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    resume() generates (Result retval);
+
+    /**
+     * Returns whether HAL supports draining of streams.
+     *
+     * @return supports true if draining is supported.
+     */
+    supportsDrain() generates (bool supports);
+
+    /**
+     * Requests notification when data buffered by the driver/hardware has been
+     * played. If 'setCallback' has previously been called to enable
+     * non-blocking mode, then 'drain' must not block, instead it must return
+     * quickly and completion of the drain is notified through the callback. If
+     * 'setCallback' has not been called, then 'drain' must block until
+     * completion.
+     *
+     * If 'type' is 'ALL', the drain completes when all previously written data
+     * has been played.
+     *
+     * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data
+     * for the current track has played to allow time for the framework to
+     * perform a gapless track switch.
+     *
+     * Drain must return immediately on 'stop' and 'flush' calls.
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @param type type of drain.
+     * @return retval operation completion status.
+     */
+    drain(AudioDrain type) generates (Result retval);
+
+    /**
+     * Notifies to the audio driver to flush the queued data. Stream must
+     * already be paused before calling 'flush'.
+     * Optional method
+     *
+     * Implementation of this function is mandatory for offloaded playback.
+     *
+     * @return retval operation completion status.
+     */
+    flush() generates (Result retval);
+
+    /**
+     * Return a recent count of the number of audio frames presented to an
+     * external observer. This excludes frames which have been written but are
+     * still in the pipeline. The count is not reset to zero when output enters
+     * standby. Also returns the value of CLOCK_MONOTONIC as of this
+     * presentation count. The returned count is expected to be 'recent', but
+     * does not need to be the most recent possible value. However, the
+     * associated time must correspond to whatever count is returned.
+     *
+     * Example: assume that N+M frames have been presented, where M is a 'small'
+     * number. Then it is permissible to return N instead of N+M, and the
+     * timestamp must correspond to N rather than N+M. The terms 'recent' and
+     * 'small' are not defined. They reflect the quality of the implementation.
+     *
+     * Optional method
+     *
+     * @return retval operation completion status.
+     * @return frames count of presented audio frames.
+     * @return timeStamp associated clock time.
+     */
+    getPresentationPosition()
+            generates (Result retval, uint64_t frames, TimeSpec timeStamp);
+};
diff --git a/audio/4.0/IStreamOutCallback.hal b/audio/4.0/IStreamOutCallback.hal
new file mode 100644
index 0000000..9a19d32
--- /dev/null
+++ b/audio/4.0/IStreamOutCallback.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+/**
+ * Asynchronous write callback interface.
+ */
+interface IStreamOutCallback {
+    /**
+     * Non blocking write completed.
+     */
+    oneway onWriteReady();
+
+    /**
+     * Drain completed.
+     */
+    oneway onDrainReady();
+
+    /**
+     * Stream hit an error.
+     */
+    oneway onError();
+};
diff --git a/audio/4.0/config/audio_policy_configuration.xsd b/audio/4.0/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..924fb47
--- /dev/null
+++ b/audio/4.0/config/audio_policy_configuration.xsd
@@ -0,0 +1,594 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+         Licensed under the Apache License, Version 2.0 (the "License");
+         you may not use this file except in compliance with the License.
+         You may obtain a copy of the License at
+
+                    http://www.apache.org/licenses/LICENSE-2.0
+
+         Unless required by applicable law or agreed to in writing, software
+         distributed under the License is distributed on an "AS IS" BASIS,
+         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+         See the License for the specific language governing permissions and
+         limitations under the License.
+-->
+<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
+<xs:schema version="2.0"
+           elementFormDefault="qualified"
+           attributeFormDefault="unqualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <!-- List the config versions supported by audio policy. -->
+    <xs:simpleType name="version">
+        <xs:restriction base="xs:decimal">
+            <xs:enumeration value="1.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="halVersion">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Version of the interface the hal implements.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:decimal">
+            <!-- List of HAL versions supported by the framework. -->
+            <xs:enumeration value="2.0"/>
+            <xs:enumeration value="3.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="audioPolicyConfiguration">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="globalConfiguration" type="globalConfiguration"/>
+                <xs:element name="modules" type="modules" maxOccurs="unbounded"/>
+                <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/>
+            </xs:sequence>
+            <xs:attribute name="version" type="version"/>
+        </xs:complexType>
+        <xs:key name="moduleNameKey">
+            <xs:selector xpath="modules/module"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:unique name="volumeTargetUniqueness">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@stream"/>
+            <xs:field xpath="@deviceCategory"/>
+        </xs:unique>
+        <xs:key name="volumeCurveNameKey">
+            <xs:selector xpath="volumes/reference"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@ref"/>
+        </xs:keyref>
+    </xs:element>
+    <xs:complexType name="globalConfiguration">
+        <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+    </xs:complexType>
+    <!-- Enum values of IDevicesFactory::Device
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="halName">
+        <xs:union>
+            <xs:simpleType>
+                <xs:restriction base="xs:string">
+                    <xs:enumeration value="primary"/>
+                    <xs:enumeration value="a2dp"/>
+                    <xs:enumeration value="usb"/>
+                    <xs:enumeration value="r_submix"/>
+                    <xs:enumeration value="codec_offload"/>
+                    <xs:enumeration value="stub"/>
+                </xs:restriction>
+            </xs:simpleType>
+            <xs:simpleType>
+                <xs:annotation>
+                    <xs:documentation xml:lang="en">
+                        Vendor eXtension names must be in the vx namespace.
+                        Vendor are encouraged to namespace their module names.
+                        Example for an hypothetical Google virtual reality HAL:
+                            <module name="vx_google_vr" halVersion="3.0"/>
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:restriction base="xs:string">
+                    <xs:pattern value="vx_[_a-zA-Z0-9]+"/>
+                </xs:restriction>
+            </xs:simpleType>
+        </xs:union>
+    </xs:simpleType>
+    <xs:complexType name="modules">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                There should be one section per audio HW module present on the platform.
+                Each <module/> contains two mandatory tags: “halVersion” and “name”.
+                The module "name" is the same as in previous .conf file.
+                Each module must contain the following sections:
+                 - <devicePorts/>: a list of device descriptors for all
+                   input and output devices accessible via this module.
+                   This contains both permanently attached devices and removable devices.
+                 - <mixPorts/>: listing all output and input streams exposed by the audio HAL
+                 - <routes/>: list of possible connections between input
+                   and output devices or between stream and devices.
+                   A <route/> is defined by a set of 3 attributes:
+                        -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix)
+                        -"sink": the sink involved in this route
+                        -"sources": all the sources than can be connected to the sink via this route
+                 - <attachedDevices/>: permanently attached devices.
+                   The attachedDevices section is a list of devices names.
+                   Their names correspond to device names defined in "devicePorts" section.
+                 - <defaultOutputDevice/> is the device to be used when no policy rule applies
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="module" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0">
+                            <xs:unique name="attachedDevicesUniqueness">
+                                <xs:selector xpath="item"/>
+                                <xs:field xpath="."/>
+                            </xs:unique>
+                        </xs:element>
+                        <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/>
+                        <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/>
+                        <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
+                        <xs:element name="routes" type="routes" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="halName" use="required"/>
+                    <xs:attribute name="halVersion" type="halVersion" use="required"/>
+                </xs:complexType>
+                <xs:unique name="mixPortNameUniqueness">
+                    <xs:selector xpath="mixPorts/mixPort"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+                <xs:key name="devicePortNameKey">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@tagName"/>
+                </xs:key>
+                <xs:unique name="devicePortUniqueness">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@type"/>
+                    <xs:field xpath="@address"/>
+                </xs:unique>
+                <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="defaultOutputDevice"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="attachedDevices/item"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <!-- The following 3 constraints try to make sure each sink port
+                     is reference in one an only one route. -->
+                <xs:key name="routeSinkKey">
+                    <!-- predicate [@type='sink'] does not work in xsd 1.0 -->
+                    <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/>
+                    <xs:field xpath="@tagName|@name"/>
+                </xs:key>
+                <xs:keyref name="routeSinkRef" refer="routeSinkKey">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:keyref>
+                <xs:unique name="routeUniqueness">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="attachedDevices">
+        <xs:sequence>
+            <xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- TODO: separate values by space for better xsd validations. -->
+    <xs:simpleType name="audioInOutFlags">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                "|" separated list of audio_output_flags_t or audio_input_flags_t.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="|[_A-Z]+(\|[_A-Z]+)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="role">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="sink"/>
+            <xs:enumeration value="source"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="mixPorts">
+        <xs:sequence>
+            <xs:element name="mixPort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:token" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="flags" type="audioInOutFlags"/>
+                    <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/>
+                    <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/>
+                    <xs:attribute name="preferredUsage" type="audioUsageList">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                When choosing the mixPort of an audio track, the audioPolicy
+                                first considers the mixPorts with a preferredUsage including
+                                the track AudioUsage preferred .
+                                If non support the track format, the other mixPorts are considered.
+                                Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive
+                                    the audio of all apps playing with a MEDIA usage.
+                                    It may receive audio from ALARM if there are no audio compatible
+                                    <mixPort preferredUsage="AUDIO_USAGE_ALARM" />.
+                             </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                </xs:complexType>
+                <xs:unique name="mixPortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="mixPortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- Enum values of audio_device_t in audio.h
+         TODO: generate from hidl to avoid manual sync.
+         TODO: separate source and sink in the xml for better xsd validations. -->
+    <xs:simpleType name="audioDevice">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_DEVICE_NONE"/>
+
+            <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ALL_SCO"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ALL_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ALL_USB"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/>
+
+            <!-- Due to the xml format, IN types can not be a separated from OUT types -->
+            <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ALL_SCO"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ALL_USB"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of audio_format_t in audio.h
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="audioFormat">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
+            <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRC"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP2"/>
+            <xs:enumeration value="AUDIO_FORMAT_QCELP"/>
+            <xs:enumeration value="AUDIO_FORMAT_DSD"/>
+            <xs:enumeration value="AUDIO_FORMAT_FLAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_ALAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_SBC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC4"/>
+            <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of audio::common::4_0::AudioUsage
+         TODO: generate from HIDL to avoid manual sync. -->
+    <xs:simpleType name="audioUsage">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
+            <xs:enumeration value="AUDIO_USAGE_MEDIA" />
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+            <xs:enumeration value="AUDIO_USAGE_ALARM" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+            <xs:enumeration value="AUDIO_USAGE_GAME" />
+            <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioUsageList">
+        <xs:list itemType="audioUsage"/>
+    </xs:simpleType>
+    <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
+    <xs:simpleType name="samplingRates">
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[0-9]+(,[0-9]+)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
+    <xs:simpleType name="channelMask">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Comma (",") separated list of channel flags
+                from audio_channel_mask_t.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[_A-Z][_A-Z0-9]*(,[_A-Z][_A-Z0-9]*)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="profile">
+        <xs:attribute name="name" type="xs:token" use="optional"/>
+        <xs:attribute name="format" type="audioFormat" use="optional"/>
+        <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
+        <xs:attribute name="channelMasks" type="channelMask" use="optional"/>
+    </xs:complexType>
+    <xs:simpleType name="gainMode">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_GAIN_MODE_JOINT"/>
+            <xs:enumeration value="AUDIO_GAIN_MODE_CHANNELS"/>
+            <xs:enumeration value="AUDIO_GAIN_MODE_RAMP"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="gains">
+        <xs:sequence>
+            <xs:element name="gain" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="xs:token" use="required"/>
+                    <xs:attribute name="mode" type="gainMode" use="required"/>
+                    <xs:attribute name="channel_mask" type="channelMask" use="optional"/>
+                    <xs:attribute name="minValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="maxValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="defaultValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
+                    <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="devicePorts">
+        <xs:sequence>
+            <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="tagName" type="xs:token" use="required"/>
+                    <xs:attribute name="type" type="audioDevice" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="address" type="xs:string" use="optional" default=""/>
+                    <!-- Note that XSD 1.0 can not check that a type only has one default. -->
+                    <xs:attribute name="default" type="xs:boolean" use="optional">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                The default device will be used if multiple have the same type
+                                and no explicit route request exists for a specific device of
+                                that type.
+                            </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                </xs:complexType>
+                <xs:unique name="devicePortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="devicePortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="mixType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="mix"/>
+            <xs:enumeration value="mux"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="routes">
+        <xs:sequence>
+            <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+                <xs:annotation>
+                    <xs:documentation xml:lang="en">
+                        List all available sources for a given sink.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:complexType>
+                    <xs:attribute name="type" type="mixType" use="required"/>
+                    <xs:attribute name="sink" type="xs:string" use="required"/>
+                    <xs:attribute name="sources" type="xs:string" use="required"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="volumes">
+        <xs:sequence>
+            <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded">
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- TODO: Always require a ref for better xsd validations.
+               Currently a volume could have no points nor ref
+               as it can not be forbidden by xsd 1.0.-->
+    <xs:simpleType name="volumePoint">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Comma separated pair of number.
+                The fist one is the framework level (between 0 and 100).
+                The second one is the volume to send to the HAL.
+                The framework will interpolate volumes not specified.
+                Their MUST be at least 2 points specified.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of audio_stream_type_t in audio-base.h
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="stream">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+            <xs:enumeration value="AUDIO_STREAM_RING"/>
+            <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+            <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+            <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+            <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+            <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+            <xs:enumeration value="AUDIO_STREAM_TTS"/>
+            <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+            <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
+            <xs:enumeration value="AUDIO_STREAM_PATCH"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of device_category from Volume.h.
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="deviceCategory">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+            <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="volume">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Volume section defines a volume curve for a given use case and device category.
+                It contains a list of points of this curve expressing the attenuation in Millibels
+                for a given volume index from 0 to 100.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </volume>
+
+                It may also reference a reference/@name to avoid duplicating curves.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                        ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+                <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </reference>
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="stream" type="stream"/>
+        <xs:attribute name="deviceCategory" type="deviceCategory"/>
+        <xs:attribute name="ref" type="xs:token" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="reference">
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="name" type="xs:token" use="required"/>
+    </xs:complexType>
+</xs:schema>
diff --git a/audio/4.0/types.hal b/audio/4.0/types.hal
new file mode 100644
index 0000000..7853f3c
--- /dev/null
+++ b/audio/4.0/types.hal
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio@4.0;
+
+import android.hardware.audio.common@4.0;
+
+enum Result : int32_t {
+    OK,
+    NOT_INITIALIZED,
+    INVALID_ARGUMENTS,
+    INVALID_STATE,
+    NOT_SUPPORTED
+};
+
+@export(name="audio_drain_type_t", value_prefix="AUDIO_DRAIN_")
+enum AudioDrain : int32_t {
+    /** drain() returns when all data has been played. */
+    ALL,
+    /**
+     * drain() returns a short time before all data from the current track has
+     * been played to give time for gapless track switch.
+     */
+    EARLY_NOTIFY
+};
+
+/**
+ * A substitute for POSIX timespec.
+ */
+struct TimeSpec {
+    uint64_t tvSec;   // seconds
+    uint64_t tvNSec;  // nanoseconds
+};
+
+/**
+ * IEEE 802 MAC address.
+ */
+typedef uint8_t[6] MacAddress;
+
+struct ParameterValue {
+    string key;
+    string value;
+};
+
+/**
+ * Specifies a device in case when several devices of the same type
+ * can be connected (e.g. BT A2DP, USB).
+ */
+struct DeviceAddress {
+    AudioDevice device;  // discriminator
+    union Address {
+        MacAddress mac;     // used for BLUETOOTH_A2DP_*
+        uint8_t[4] ipv4;    // used for IP
+        struct Alsa {
+            int32_t card;
+            int32_t device;
+        } alsa;             // used for USB_*
+    } address;
+    string busAddress;      // used for BUS
+    string rSubmixAddress;  // used for REMOTE_SUBMIX
+};
+
+enum MmapBufferFlag : uint32_t {
+    NONE    = 0x0,
+    /**
+     * If the buffer can be securely shared to untrusted applications
+     * through the AAudio exclusive mode.
+     * Only set this flag if applications are restricted from accessing the
+     * memory surrounding the audio data buffer by a kernel mechanism.
+     * See Linux kernel's dma_buf.
+     */
+    APPLICATION_SHAREABLE    = 0x1,
+};
+
+/**
+ * Mmap buffer descriptor returned by IStream.createMmapBuffer().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapBufferInfo {
+    /** Mmap memory buffer */
+    memory  sharedMemory;
+    /** Total buffer size in frames */
+    uint32_t bufferSizeFrames;
+    /** Transfer size granularity in frames */
+    uint32_t burstSizeFrames;
+    /** Attributes describing the buffer. */
+    bitfield<MmapBufferFlag> flags;
+};
+
+/**
+ * Mmap buffer read/write position returned by IStream.getMmapPosition().
+ * Used by streams opened in mmap mode.
+ */
+struct MmapPosition {
+    int64_t  timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC
+    int32_t  positionFrames;  // increasing 32 bit frame count reset when IStream.stop() is called
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * message queues used by StreamIn and StreamOut.
+ */
+enum MessageQueueFlagBits : uint32_t {
+    NOT_EMPTY = 1 << 0,
+    NOT_FULL = 1 << 1
+};
+
+/** Metadata of a playback track for a StreamOut. */
+struct PlaybackTrackMetadata {
+    AudioUsage usage;
+    AudioContentType contentType;
+    /**
+     * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+     * 2 means double amplification...
+     * Must not be negative.
+     */
+    float gain;
+};
+
+/** Metadatas of the source of a StreamOut. */
+struct SourceMetadata {
+    vec<PlaybackTrackMetadata> tracks;
+};
+
+/** Metadata of a record track for a StreamIn. */
+struct RecordTrackMetadata {
+    AudioSource source;
+    /**
+     * Positive linear gain applied to the track samples. 0 being muted and 1 is no attenuation,
+     * 2 means double amplification...
+     * Must not be negative.
+     */
+    float gain;
+};
+
+/** Metadatas of the source of a StreamIn. */
+struct SinkMetadata {
+    vec<RecordTrackMetadata> tracks;
+};
+
+/*
+ * Microphone information
+ *
+ */
+
+/**
+ * A 3D point used to represent position or orientation of a microphone.
+ *
+ * Position: Coordinates of the microphone's capsule, in meters, from the
+ * bottom-left-back corner of the bounding box of android device in natural
+ * orientation (PORTRAIT for phones, LANDSCAPE for tablets, tvs, etc).
+ * The orientation musth match the reported by the api Display.getRotation().
+ *
+ * Orientation: Normalized vector to signal the main orientation of the
+ * microphone's capsule. Magnitude = sqrt(x^2 + y^2 + z^2) = 1
+ */
+struct AudioMicrophoneCoordinate {
+    float x;
+    float y;
+    float z;
+};
+
+/**
+ * Enum to identify the type of channel mapping for active microphones.
+ * Used channels further identify if the microphone has any significative
+ * process (e.g. High Pass Filtering, dynamic compression)
+ * Simple processing as constant gain adjustment must be DIRECT.
+ */
+enum AudioMicrophoneChannelMapping : uint32_t {
+    UNUSED      = 0, /** Channel not used */
+    DIRECT      = 1, /** Channel used and signal not processed */
+    PROCESSED   = 2, /** Channel used and signal has some process */
+};
+
+/**
+ * Enum to identify locations of microphones in regards to the body of the
+ * android device.
+ */
+enum AudioMicrophoneLocation : uint32_t {
+    UNKNOWN             = 0,
+    MAINBODY            = 1,
+    MAINBODY_MOVABLE    = 2,
+    PERIPHERAL          = 3,
+};
+
+/**
+ * Identifier to help group related microphones together
+ * e.g. microphone arrays should belong to the same group
+ */
+typedef int32_t AudioMicrophoneGroup;
+
+/**
+ * Enum with standard polar patterns of microphones
+ */
+enum AudioMicrophoneDirectionality : uint32_t {
+    UNKNOWN         = 0,
+    OMNI            = 1,
+    BI_DIRECTIONAL  = 2,
+    CARDIOID        = 3,
+    HYPER_CARDIOID  = 4,
+    SUPER_CARDIOID  = 5,
+};
+
+/**
+ * A (frequency, level) pair. Used to represent frequency response.
+ */
+struct AudioFrequencyResponsePoint {
+    /** In Hz */
+    float frequency;
+    /** In dB */
+    float level;
+};
+
+/**
+ * Structure used by the HAL to describe microphone's characteristics
+ * Used by StreamIn and Device
+ */
+struct MicrophoneInfo {
+    /** Unique alphanumeric id for microphone. Guaranteed to be the same
+     * even after rebooting.
+     */
+    string                                  deviceId;
+    /**
+     * Device specific information
+     */
+    DeviceAddress                           deviceAddress;
+    /** Each element of the vector must describe the channel with the same
+     *  index.
+     */
+    vec<AudioMicrophoneChannelMapping>      channelMapping;
+    /** Location of the microphone in regard to the body of the device */
+    AudioMicrophoneLocation                 location;
+    /** Identifier to help group related microphones together
+     *  e.g. microphone arrays should belong to the same group
+     */
+    AudioMicrophoneGroup                    group;
+    /** Index of this microphone within the group.
+     *  (group, index) must be unique within the same device.
+     */
+    uint32_t                                indexInTheGroup;
+    /** Level in dBFS produced by a 1000 Hz tone at 94 dB SPL */
+    float                                   sensitivity;
+    /** Level in dB of the max SPL supported at 1000 Hz */
+    float                                   maxSpl;
+    /** Level in dB of the min SPL supported at 1000 Hz */
+    float                                   minSpl;
+    /** Standard polar pattern of the microphone */
+    AudioMicrophoneDirectionality           directionality;
+    /** Vector with ordered frequency responses (from low to high frequencies)
+     *  with the frequency response of the microphone.
+     *  Levels are in dB, relative to level at 1000 Hz
+     */
+    vec<AudioFrequencyResponsePoint>        frequencyResponse;
+    /** Position of the microphone's capsule in meters, from the
+     *  bottom-left-back corner of the bounding box of device.
+     */
+    AudioMicrophoneCoordinate               position;
+    /** Normalized point to signal the main orientation of the microphone's
+     *  capsule. sqrt(x^2 + y^2 + z^2) = 1
+     */
+    AudioMicrophoneCoordinate               orientation;
+};
diff --git a/audio/README b/audio/README
new file mode 100644
index 0000000..1f1e8e3
--- /dev/null
+++ b/audio/README
@@ -0,0 +1,48 @@
+Directory structure of the audio HIDL related code.
+
+audio
+|-- 2.0              <== HIDL (.hal) can not be moved to fit the directory structure
+|                        because that would create a separate HAL
+|-- 4.0              <== Version 4.0 of the core API
+|
+|-- common           <== code common to audio core and effect API
+|   |-- 2.0
+|   |   |-- default  <== code that wraps the legacy API
+|   |   `-- vts      <== vts of 2.0 core and effect API common code
+|   |-- 4.0
+|   |   |-- default
+|   |   `-- vts
+|   |-- ...          <== The future versions should continue this structure
+|   |   |-- default
+|   |   `-- vts
+|   `-- all_versions <== code common to all version of both core and effect API
+|       |-- default
+|       `-- vts      <== vts of core and effect API common version independent code
+|
+|-- core           <== code relative to the core API
+|   |-- 2.0          <== 2.0 core API code (except .hal, see audio/2.0)
+|   |   |-- default
+|   |   `-- vts
+|   |-- 4.0
+|   |   |-- default  <== default implementation of the core 4.0 api
+|   |   `-- vts      <== vts code of the 4.0 API
+|   |-- ...
+|   |   |-- default
+|   |   `-- vts
+|   `-- all_versions
+|       |-- default
+|       `-- vts      <== vts of core API common version independent code
+|
+`-- effect           <== idem for the effect API
+    |-- 2.0
+    |   |-- default
+    |   `-- vts
+    |-- 4.0
+    |   |-- default
+    |   `-- vts
+    |-- ...
+    |   |-- default
+    |   `-- vts
+    `-- all_versions
+        |-- default
+        `-- vts
diff --git a/audio/common/2.0/default/Android.bp b/audio/common/2.0/default/Android.bp
index 82b38c0..ac66479 100644
--- a/audio/common/2.0/default/Android.bp
+++ b/audio/common/2.0/default/Android.bp
@@ -21,18 +21,24 @@
         enabled: true,
     },
     srcs: [
-        "EffectMap.cpp",
         "HidlUtils.cpp",
     ],
 
     export_include_dirs: ["."],
 
+    static_libs: [
+    ],
+
     shared_libs: [
         "liblog",
         "libutils",
         "libhidlbase",
+        "android.hardware.audio.common-util",
         "android.hardware.audio.common@2.0",
     ],
+    export_shared_lib_headers: [
+        "android.hardware.audio.common-util"
+    ],
 
     header_libs: [
         "libaudio_system_headers",
diff --git a/audio/common/2.0/default/EffectMap.cpp b/audio/common/2.0/default/EffectMap.cpp
deleted file mode 100644
index 703b91c..0000000
--- a/audio/common/2.0/default/EffectMap.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-#include <atomic>
-
-#include "EffectMap.h"
-
-namespace android {
-
-ANDROID_SINGLETON_STATIC_INSTANCE(EffectMap);
-
-// static
-const uint64_t EffectMap::INVALID_ID = 0;
-
-// static
-uint64_t EffectMap::makeUniqueId() {
-    static std::atomic<uint64_t> counter{INVALID_ID + 1};
-    return counter++;
-}
-
-uint64_t EffectMap::add(effect_handle_t handle) {
-    uint64_t newId = makeUniqueId();
-    std::lock_guard<std::mutex> lock(mLock);
-    mEffects.add(newId, handle);
-    return newId;
-}
-
-effect_handle_t EffectMap::get(const uint64_t& id) {
-    std::lock_guard<std::mutex> lock(mLock);
-    ssize_t idx = mEffects.indexOfKey(id);
-    return idx >= 0 ? mEffects[idx] : NULL;
-}
-
-void EffectMap::remove(effect_handle_t handle) {
-    std::lock_guard<std::mutex> lock(mLock);
-    for (size_t i = 0; i < mEffects.size(); ++i) {
-        if (mEffects[i] == handle) {
-            mEffects.removeItemsAt(i);
-            break;
-        }
-    }
-}
-
-}  // namespace android
diff --git a/audio/common/2.0/default/EffectMap.h b/audio/common/2.0/default/EffectMap.h
deleted file mode 100644
index 82bbb1f..0000000
--- a/audio/common/2.0/default/EffectMap.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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_audio_V2_0_EffectMap_H_
-#define android_hardware_audio_V2_0_EffectMap_H_
-
-#include <mutex>
-
-#include <hardware/audio_effect.h>
-#include <utils/KeyedVector.h>
-#include <utils/Singleton.h>
-
-namespace android {
-
-// This class needs to be in 'android' ns because Singleton macros require that.
-class EffectMap : public Singleton<EffectMap> {
-  public:
-    static const uint64_t INVALID_ID;
-
-    uint64_t add(effect_handle_t handle);
-    effect_handle_t get(const uint64_t& id);
-    void remove(effect_handle_t handle);
-
-  private:
-    static uint64_t makeUniqueId();
-
-    std::mutex mLock;
-    KeyedVector<uint64_t, effect_handle_t> mEffects;
-};
-
-}  // namespace android
-
-#endif  // android_hardware_audio_V2_0_EffectMap_H_
diff --git a/audio/common/2.0/default/HidlUtils.cpp b/audio/common/2.0/default/HidlUtils.cpp
index 79cb37c..9771b7b 100644
--- a/audio/common/2.0/default/HidlUtils.cpp
+++ b/audio/common/2.0/default/HidlUtils.cpp
@@ -14,324 +14,8 @@
  * limitations under the License.
  */
 
-#include <string.h>
-
 #include "HidlUtils.h"
 
-using ::android::hardware::audio::common::V2_0::AudioChannelMask;
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioFormat;
-using ::android::hardware::audio::common::V2_0::AudioGainMode;
-using ::android::hardware::audio::common::V2_0::AudioMixLatencyClass;
-using ::android::hardware::audio::common::V2_0::AudioPortConfigMask;
-using ::android::hardware::audio::common::V2_0::AudioPortRole;
-using ::android::hardware::audio::common::V2_0::AudioPortType;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::common::V2_0::AudioStreamType;
-using ::android::hardware::audio::common::V2_0::AudioUsage;
-
-namespace android {
-
-void HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config) {
-    config->sampleRateHz = halConfig.sample_rate;
-    config->channelMask = AudioChannelMask(halConfig.channel_mask);
-    config->format = AudioFormat(halConfig.format);
-    audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo);
-    config->frameCount = halConfig.frame_count;
-}
-
-void HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) {
-    memset(halConfig, 0, sizeof(audio_config_t));
-    halConfig->sample_rate = config.sampleRateHz;
-    halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
-    halConfig->format = static_cast<audio_format_t>(config.format);
-    audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info);
-    halConfig->frame_count = config.frameCount;
-}
-
-void HidlUtils::audioGainConfigFromHal(
-        const struct audio_gain_config& halConfig, AudioGainConfig* config) {
-    config->index = halConfig.index;
-    config->mode = AudioGainMode(halConfig.mode);
-    config->channelMask = AudioChannelMask(halConfig.channel_mask);
-    for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) {
-        config->values[i] = halConfig.values[i];
-    }
-    config->rampDurationMs = halConfig.ramp_duration_ms;
-}
-
-void HidlUtils::audioGainConfigToHal(
-        const AudioGainConfig& config, struct audio_gain_config* halConfig) {
-    halConfig->index = config.index;
-    halConfig->mode = static_cast<audio_gain_mode_t>(config.mode);
-    halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
-    memset(halConfig->values, 0, sizeof(halConfig->values));
-    for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) {
-        halConfig->values[i] = config.values[i];
-    }
-    halConfig->ramp_duration_ms = config.rampDurationMs;
-}
-
-void HidlUtils::audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain) {
-    gain->mode = AudioGainMode(halGain.mode);
-    gain->channelMask = AudioChannelMask(halGain.channel_mask);
-    gain->minValue = halGain.min_value;
-    gain->maxValue = halGain.max_value;
-    gain->defaultValue = halGain.default_value;
-    gain->stepValue = halGain.step_value;
-    gain->minRampMs = halGain.min_ramp_ms;
-    gain->maxRampMs = halGain.max_ramp_ms;
-}
-
-void HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) {
-    halGain->mode = static_cast<audio_gain_mode_t>(gain.mode);
-    halGain->channel_mask = static_cast<audio_channel_mask_t>(gain.channelMask);
-    halGain->min_value = gain.minValue;
-    halGain->max_value = gain.maxValue;
-    halGain->default_value = gain.defaultValue;
-    halGain->step_value = gain.stepValue;
-    halGain->min_ramp_ms = gain.minRampMs;
-    halGain->max_ramp_ms = gain.maxRampMs;
-}
-
-void HidlUtils::audioOffloadInfoFromHal(
-        const audio_offload_info_t& halOffload, AudioOffloadInfo* offload) {
-    offload->sampleRateHz = halOffload.sample_rate;
-    offload->channelMask = AudioChannelMask(halOffload.channel_mask);
-    offload->format = AudioFormat(halOffload.format);
-    offload->streamType = AudioStreamType(halOffload.stream_type);
-    offload->bitRatePerSecond = halOffload.bit_rate;
-    offload->durationMicroseconds = halOffload.duration_us;
-    offload->hasVideo = halOffload.has_video;
-    offload->isStreaming = halOffload.is_streaming;
-    offload->bitWidth = halOffload.bit_width;
-    offload->bufferSize = halOffload.offload_buffer_size;
-    offload->usage = static_cast<AudioUsage>(halOffload.usage);
-}
-
-void HidlUtils::audioOffloadInfoToHal(
-        const AudioOffloadInfo& offload, audio_offload_info_t* halOffload) {
-    *halOffload = AUDIO_INFO_INITIALIZER;
-    halOffload->sample_rate = offload.sampleRateHz;
-    halOffload->channel_mask = static_cast<audio_channel_mask_t>(offload.channelMask);
-    halOffload->format = static_cast<audio_format_t>(offload.format);
-    halOffload->stream_type = static_cast<audio_stream_type_t>(offload.streamType);
-    halOffload->bit_rate = offload.bitRatePerSecond;
-    halOffload->duration_us = offload.durationMicroseconds;
-    halOffload->has_video = offload.hasVideo;
-    halOffload->is_streaming = offload.isStreaming;
-    halOffload->bit_width = offload.bitWidth;
-    halOffload->offload_buffer_size = offload.bufferSize;
-    halOffload->usage = static_cast<audio_usage_t>(offload.usage);
-}
-
-void HidlUtils::audioPortConfigFromHal(
-        const struct audio_port_config& halConfig, AudioPortConfig* config) {
-    config->id = halConfig.id;
-    config->role = AudioPortRole(halConfig.role);
-    config->type = AudioPortType(halConfig.type);
-    config->configMask = AudioPortConfigMask(halConfig.config_mask);
-    config->sampleRateHz = halConfig.sample_rate;
-    config->channelMask = AudioChannelMask(halConfig.channel_mask);
-    config->format = AudioFormat(halConfig.format);
-    audioGainConfigFromHal(halConfig.gain, &config->gain);
-    switch (halConfig.type) {
-        case AUDIO_PORT_TYPE_NONE: break;
-        case AUDIO_PORT_TYPE_DEVICE: {
-            config->ext.device.hwModule = halConfig.ext.device.hw_module;
-            config->ext.device.type = AudioDevice(halConfig.ext.device.type);
-            memcpy(config->ext.device.address.data(),
-                    halConfig.ext.device.address,
-                    AUDIO_DEVICE_MAX_ADDRESS_LEN);
-            break;
-        }
-        case AUDIO_PORT_TYPE_MIX: {
-            config->ext.mix.hwModule = halConfig.ext.mix.hw_module;
-            config->ext.mix.ioHandle = halConfig.ext.mix.handle;
-            if (halConfig.role == AUDIO_PORT_ROLE_SOURCE) {
-                config->ext.mix.useCase.source = AudioSource(halConfig.ext.mix.usecase.source);
-            } else if (halConfig.role == AUDIO_PORT_ROLE_SINK) {
-                config->ext.mix.useCase.stream = AudioStreamType(halConfig.ext.mix.usecase.stream);
-            }
-            break;
-        }
-        case AUDIO_PORT_TYPE_SESSION: {
-            config->ext.session.session = halConfig.ext.session.session;
-            break;
-        }
-    }
-}
-
-void HidlUtils::audioPortConfigToHal(
-        const AudioPortConfig& config, struct audio_port_config* halConfig) {
-    memset(halConfig, 0, sizeof(audio_port_config));
-    halConfig->id = config.id;
-    halConfig->role = static_cast<audio_port_role_t>(config.role);
-    halConfig->type = static_cast<audio_port_type_t>(config.type);
-    halConfig->config_mask = static_cast<unsigned int>(config.configMask);
-    halConfig->sample_rate = config.sampleRateHz;
-    halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
-    halConfig->format = static_cast<audio_format_t>(config.format);
-    audioGainConfigToHal(config.gain, &halConfig->gain);
-    switch (config.type) {
-        case AudioPortType::NONE: break;
-        case AudioPortType::DEVICE: {
-            halConfig->ext.device.hw_module = config.ext.device.hwModule;
-            halConfig->ext.device.type = static_cast<audio_devices_t>(config.ext.device.type);
-            memcpy(halConfig->ext.device.address,
-                    config.ext.device.address.data(),
-                    AUDIO_DEVICE_MAX_ADDRESS_LEN);
-            break;
-        }
-        case AudioPortType::MIX: {
-            halConfig->ext.mix.hw_module = config.ext.mix.hwModule;
-            halConfig->ext.mix.handle = config.ext.mix.ioHandle;
-            if (config.role == AudioPortRole::SOURCE) {
-                halConfig->ext.mix.usecase.source =
-                        static_cast<audio_source_t>(config.ext.mix.useCase.source);
-            } else if (config.role == AudioPortRole::SINK) {
-                halConfig->ext.mix.usecase.stream =
-                        static_cast<audio_stream_type_t>(config.ext.mix.useCase.stream);
-            }
-            break;
-        }
-        case AudioPortType::SESSION: {
-            halConfig->ext.session.session =
-                    static_cast<audio_session_t>(config.ext.session.session);
-            break;
-        }
-    }
-}
-
-void HidlUtils::audioPortConfigsFromHal(
-        unsigned int numHalConfigs, const struct audio_port_config *halConfigs,
-        hidl_vec<AudioPortConfig> *configs) {
-    configs->resize(numHalConfigs);
-    for (unsigned int i = 0; i < numHalConfigs; ++i) {
-        audioPortConfigFromHal(halConfigs[i], &(*configs)[i]);
-    }
-}
-
-std::unique_ptr<audio_port_config[]> HidlUtils::audioPortConfigsToHal(
-        const hidl_vec<AudioPortConfig>& configs) {
-    std::unique_ptr<audio_port_config[]> halConfigs(new audio_port_config[configs.size()]);
-    for (size_t i = 0; i < configs.size(); ++i) {
-        audioPortConfigToHal(configs[i], &halConfigs[i]);
-    }
-    return halConfigs;
-}
-
-void HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) {
-    port->id = halPort.id;
-    port->role = AudioPortRole(halPort.role);
-    port->type = AudioPortType(halPort.type);
-    port->name.setToExternal(halPort.name, strlen(halPort.name));
-    port->sampleRates.resize(halPort.num_sample_rates);
-    for (size_t i = 0; i < halPort.num_sample_rates; ++i) {
-        port->sampleRates[i] = halPort.sample_rates[i];
-    }
-    port->channelMasks.resize(halPort.num_channel_masks);
-    for (size_t i = 0; i < halPort.num_channel_masks; ++i) {
-        port->channelMasks[i] = AudioChannelMask(halPort.channel_masks[i]);
-    }
-    port->formats.resize(halPort.num_formats);
-    for (size_t i = 0; i < halPort.num_formats; ++i) {
-        port->formats[i] = AudioFormat(halPort.formats[i]);
-    }
-    port->gains.resize(halPort.num_gains);
-    for (size_t i = 0; i < halPort.num_gains; ++i) {
-        audioGainFromHal(halPort.gains[i], &port->gains[i]);
-    }
-    audioPortConfigFromHal(halPort.active_config, &port->activeConfig);
-    switch (halPort.type) {
-        case AUDIO_PORT_TYPE_NONE: break;
-        case AUDIO_PORT_TYPE_DEVICE: {
-            port->ext.device.hwModule = halPort.ext.device.hw_module;
-            port->ext.device.type = AudioDevice(halPort.ext.device.type);
-            memcpy(port->ext.device.address.data(),
-                    halPort.ext.device.address,
-                    AUDIO_DEVICE_MAX_ADDRESS_LEN);
-            break;
-        }
-        case AUDIO_PORT_TYPE_MIX: {
-            port->ext.mix.hwModule = halPort.ext.mix.hw_module;
-            port->ext.mix.ioHandle = halPort.ext.mix.handle;
-            port->ext.mix.latencyClass = AudioMixLatencyClass(halPort.ext.mix.latency_class);
-            break;
-        }
-        case AUDIO_PORT_TYPE_SESSION: {
-            port->ext.session.session = halPort.ext.session.session;
-            break;
-        }
-    }
-}
-
-void HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort) {
-    memset(halPort, 0, sizeof(audio_port));
-    halPort->id = port.id;
-    halPort->role = static_cast<audio_port_role_t>(port.role);
-    halPort->type = static_cast<audio_port_type_t>(port.type);
-    memcpy(halPort->name,
-            port.name.c_str(),
-            std::min(port.name.size(), static_cast<size_t>(AUDIO_PORT_MAX_NAME_LEN)));
-    halPort->num_sample_rates =
-            std::min(port.sampleRates.size(), static_cast<size_t>(AUDIO_PORT_MAX_SAMPLING_RATES));
-    for (size_t i = 0; i < halPort->num_sample_rates; ++i) {
-        halPort->sample_rates[i] = port.sampleRates[i];
-    }
-    halPort->num_channel_masks =
-            std::min(port.channelMasks.size(), static_cast<size_t>(AUDIO_PORT_MAX_CHANNEL_MASKS));
-    for (size_t i = 0; i < halPort->num_channel_masks; ++i) {
-        halPort->channel_masks[i] = static_cast<audio_channel_mask_t>(port.channelMasks[i]);
-    }
-    halPort->num_formats =
-            std::min(port.formats.size(), static_cast<size_t>(AUDIO_PORT_MAX_FORMATS));
-    for (size_t i = 0; i < halPort->num_formats; ++i) {
-        halPort->formats[i] = static_cast<audio_format_t>(port.formats[i]);
-    }
-    halPort->num_gains = std::min(port.gains.size(), static_cast<size_t>(AUDIO_PORT_MAX_GAINS));
-    for (size_t i = 0; i < halPort->num_gains; ++i) {
-        audioGainToHal(port.gains[i], &halPort->gains[i]);
-    }
-    audioPortConfigToHal(port.activeConfig, &halPort->active_config);
-    switch (port.type) {
-        case AudioPortType::NONE: break;
-        case AudioPortType::DEVICE: {
-            halPort->ext.device.hw_module = port.ext.device.hwModule;
-            halPort->ext.device.type = static_cast<audio_devices_t>(port.ext.device.type);
-            memcpy(halPort->ext.device.address,
-                    port.ext.device.address.data(),
-                    AUDIO_DEVICE_MAX_ADDRESS_LEN);
-            break;
-        }
-        case AudioPortType::MIX: {
-            halPort->ext.mix.hw_module = port.ext.mix.hwModule;
-            halPort->ext.mix.handle = port.ext.mix.ioHandle;
-            halPort->ext.mix.latency_class =
-                    static_cast<audio_mix_latency_class_t>(port.ext.mix.latencyClass);
-            break;
-        }
-        case AudioPortType::SESSION: {
-            halPort->ext.session.session = static_cast<audio_session_t>(port.ext.session.session);
-            break;
-        }
-    }
-}
-
-void HidlUtils::uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid) {
-    uuid->timeLow = halUuid.timeLow;
-    uuid->timeMid = halUuid.timeMid;
-    uuid->versionAndTimeHigh = halUuid.timeHiAndVersion;
-    uuid->variantAndClockSeqHigh = halUuid.clockSeq;
-    memcpy(uuid->node.data(), halUuid.node, uuid->node.size());
-}
-
-void HidlUtils::uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid) {
-    halUuid->timeLow = uuid.timeLow;
-    halUuid->timeMid = uuid.timeMid;
-    halUuid->timeHiAndVersion = uuid.versionAndTimeHigh;
-    halUuid->clockSeq = uuid.variantAndClockSeqHigh;
-    memcpy(halUuid->node, uuid.node.data(), uuid.node.size());
-}
-
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <common/all-versions/default/HidlUtils.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/common/2.0/default/HidlUtils.h b/audio/common/2.0/default/HidlUtils.h
index 3fde4d7..24543b1 100644
--- a/audio/common/2.0/default/HidlUtils.h
+++ b/audio/common/2.0/default/HidlUtils.h
@@ -17,51 +17,10 @@
 #ifndef android_hardware_audio_V2_0_Hidl_Utils_H_
 #define android_hardware_audio_V2_0_Hidl_Utils_H_
 
-#include <memory>
-
 #include <android/hardware/audio/common/2.0/types.h>
-#include <system/audio.h>
 
-using ::android::hardware::audio::common::V2_0::AudioConfig;
-using ::android::hardware::audio::common::V2_0::AudioGain;
-using ::android::hardware::audio::common::V2_0::AudioGainConfig;
-using ::android::hardware::audio::common::V2_0::AudioOffloadInfo;
-using ::android::hardware::audio::common::V2_0::AudioPort;
-using ::android::hardware::audio::common::V2_0::AudioPortConfig;
-using ::android::hardware::audio::common::V2_0::Uuid;
-using ::android::hardware::hidl_vec;
-
-namespace android {
-
-class HidlUtils {
-  public:
-    static void audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config);
-    static void audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig);
-    static void audioGainConfigFromHal(
-            const struct audio_gain_config& halConfig, AudioGainConfig* config);
-    static void audioGainConfigToHal(
-            const AudioGainConfig& config, struct audio_gain_config* halConfig);
-    static void audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain);
-    static void audioGainToHal(const AudioGain& gain, struct audio_gain* halGain);
-    static void audioOffloadInfoFromHal(
-            const audio_offload_info_t& halOffload, AudioOffloadInfo* offload);
-    static void audioOffloadInfoToHal(
-            const AudioOffloadInfo& offload, audio_offload_info_t* halOffload);
-    static void audioPortConfigFromHal(
-            const struct audio_port_config& halConfig, AudioPortConfig* config);
-    static void audioPortConfigToHal(
-            const AudioPortConfig& config, struct audio_port_config* halConfig);
-    static void audioPortConfigsFromHal(
-            unsigned int numHalConfigs, const struct audio_port_config *halConfigs,
-            hidl_vec<AudioPortConfig> *configs);
-    static std::unique_ptr<audio_port_config[]> audioPortConfigsToHal(
-            const hidl_vec<AudioPortConfig>& configs);
-    static void audioPortFromHal(const struct audio_port& halPort, AudioPort* port);
-    static void audioPortToHal(const AudioPort& port, struct audio_port* halPort);
-    static void uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid);
-    static void uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid);
-};
-
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <common/all-versions/default/HidlUtils.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // android_hardware_audio_V2_0_Hidl_Utils_H_
diff --git a/audio/common/4.0/Android.bp b/audio/common/4.0/Android.bp
new file mode 100644
index 0000000..9b737dc
--- /dev/null
+++ b/audio/common/4.0/Android.bp
@@ -0,0 +1,48 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio.common@4.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+    ],
+    types: [
+        "AudioChannelMask",
+        "AudioConfig",
+        "AudioContentType",
+        "AudioDevice",
+        "AudioFormat",
+        "AudioGain",
+        "AudioGainConfig",
+        "AudioGainMode",
+        "AudioHandleConsts",
+        "AudioInputFlag",
+        "AudioMixLatencyClass",
+        "AudioMode",
+        "AudioOffloadInfo",
+        "AudioOutputFlag",
+        "AudioPort",
+        "AudioPortConfig",
+        "AudioPortConfigDeviceExt",
+        "AudioPortConfigMask",
+        "AudioPortConfigSessionExt",
+        "AudioPortDeviceExt",
+        "AudioPortMixExt",
+        "AudioPortRole",
+        "AudioPortSessionExt",
+        "AudioPortType",
+        "AudioSessionConsts",
+        "AudioSource",
+        "AudioStreamType",
+        "AudioUsage",
+        "FixedChannelCount",
+        "ThreadInfo",
+        "Uuid",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
+
diff --git a/audio/common/4.0/types.hal b/audio/common/4.0/types.hal
new file mode 100644
index 0000000..d4c6efe
--- /dev/null
+++ b/audio/common/4.0/types.hal
@@ -0,0 +1,888 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.common@4.0;
+
+/*
+ *
+ *  IDs and Handles
+ *
+ */
+
+/**
+ * Handle type for identifying audio sources and sinks.
+ */
+typedef int32_t AudioIoHandle;
+
+/**
+ * Audio hw module handle functions or structures referencing a module.
+ */
+typedef int32_t AudioModuleHandle;
+
+/**
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+typedef int32_t AudioPortHandle;
+
+/**
+ * Each patch is identified by a handle at the interface used to create that
+ * patch. For instance, when a patch is created by the audio HAL, the HAL
+ * allocates and returns a handle.  This handle is unique to a given audio HAL
+ * hardware module.  But the same patch receives another system wide unique
+ * handle allocated by the framework.  This unique handle is used for all
+ * transactions inside the framework.
+ */
+typedef int32_t AudioPatchHandle;
+
+/**
+ * A HW synchronization source returned by the audio HAL.
+ */
+typedef uint32_t AudioHwSync;
+
+/**
+ * Each port has a unique ID or handle allocated by policy manager.
+ */
+@export(name="")
+enum AudioHandleConsts : int32_t {
+    AUDIO_IO_HANDLE_NONE = 0,
+    AUDIO_MODULE_HANDLE_NONE = 0,
+    AUDIO_PORT_HANDLE_NONE = 0,
+    AUDIO_PATCH_HANDLE_NONE = 0,
+};
+
+/**
+ * Commonly used structure for passing unique identifieds (UUID).
+ * For the definition of UUID, refer to ITU-T X.667 spec.
+ */
+struct Uuid {
+    uint32_t timeLow;
+    uint16_t timeMid;
+    uint16_t versionAndTimeHigh;
+    uint16_t variantAndClockSeqHigh;
+    uint8_t[6] node;
+};
+
+
+/*
+ *
+ *  Audio streams
+ *
+ */
+
+/**
+ * Audio stream type describing the intended use case of a stream.
+ */
+@export(name="audio_stream_type_t", value_prefix="AUDIO_STREAM_")
+enum AudioStreamType : int32_t {
+    // These values must kept in sync with
+    //  frameworks/base/media/java/android/media/AudioSystem.java
+    DEFAULT          = -1,
+    MIN              = 0,
+    VOICE_CALL       = 0,
+    SYSTEM           = 1,
+    RING             = 2,
+    MUSIC            = 3,
+    ALARM            = 4,
+    NOTIFICATION     = 5,
+    BLUETOOTH_SCO    = 6,
+    ENFORCED_AUDIBLE = 7,  // Sounds that cannot be muted by user and must be
+                           // routed to speaker
+    DTMF             = 8,
+    TTS              = 9,  // Transmitted Through Speaker.  Plays over speaker
+                           // only, silent on other devices
+    ACCESSIBILITY    = 10, // For accessibility talk back prompts
+    REROUTING        = 11, // For dynamic policy output mixes
+    PATCH            = 12, // For internal audio flinger tracks.  Fixed volume
+};
+
+@export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
+enum AudioSource : int32_t {
+    // These values must kept in sync with
+    //  frameworks/base/media/java/android/media/MediaRecorder.java,
+    //  frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
+    //  system/media/audio_effects/include/audio_effects/audio_effects_conf.h
+    DEFAULT             = 0,
+    MIC                 = 1,
+    VOICE_UPLINK        = 2,
+    VOICE_DOWNLINK      = 3,
+    VOICE_CALL          = 4,
+    CAMCORDER           = 5,
+    VOICE_RECOGNITION   = 6,
+    VOICE_COMMUNICATION = 7,
+    /**
+     * Source for the mix to be presented remotely. An example of remote
+     * presentation is Wifi Display where a dongle attached to a TV can be used
+     * to play the mix captured by this audio source.
+     */
+    REMOTE_SUBMIX       = 8,
+    /**
+     * Source for unprocessed sound. Usage examples include level measurement
+     * and raw signal analysis.
+     */
+    UNPROCESSED         = 9,
+
+    FM_TUNER            = 1998,
+};
+
+typedef int32_t AudioSession;
+/**
+ * Special audio session values.
+ */
+@export(name="audio_session_t", value_prefix="AUDIO_SESSION_")
+enum AudioSessionConsts : int32_t {
+    /**
+     * Session for effects attached to a particular output stream
+     * (value must be less than 0)
+     */
+    OUTPUT_STAGE = -1,
+    /**
+     * Session for effects applied to output mix. These effects can
+     * be moved by audio policy manager to another output stream
+     * (value must be 0)
+     */
+    OUTPUT_MIX = 0,
+    /**
+     * Application does not specify an explicit session ID to be used, and
+     * requests a new session ID to be allocated. Corresponds to
+     * AudioManager.AUDIO_SESSION_ID_GENERATE and
+     * AudioSystem.AUDIO_SESSION_ALLOCATE.
+     */
+    ALLOCATE = 0,
+    /**
+     * For use with AudioRecord::start(), this indicates no trigger session.
+     * It is also used with output tracks and patch tracks, which never have a
+     * session.
+     */
+    NONE = 0
+};
+
+/**
+ * Audio format  is a 32-bit word that consists of:
+ *   main format field (upper 8 bits)
+ *   sub format field (lower 24 bits).
+ *
+ * The main format indicates the main codec type. The sub format field indicates
+ * options and parameters for each format. The sub format is mainly used for
+ * record to indicate for instance the requested bitrate or profile.  It can
+ * also be used for certain formats to give informations not present in the
+ * encoded audio stream (e.g. octet alignement for AMR).
+ */
+@export(name="audio_format_t", value_prefix="AUDIO_FORMAT_")
+enum AudioFormat : uint32_t {
+    INVALID             = 0xFFFFFFFFUL,
+    DEFAULT             = 0,
+    PCM                 = 0x00000000UL,
+    MP3                 = 0x01000000UL,
+    AMR_NB              = 0x02000000UL,
+    AMR_WB              = 0x03000000UL,
+    AAC                 = 0x04000000UL,
+    /** Deprecated, Use AAC_HE_V1 */
+    HE_AAC_V1           = 0x05000000UL,
+    /** Deprecated, Use AAC_HE_V2 */
+    HE_AAC_V2           = 0x06000000UL,
+    VORBIS              = 0x07000000UL,
+    OPUS                = 0x08000000UL,
+    AC3                 = 0x09000000UL,
+    E_AC3               = 0x0A000000UL,
+    DTS                 = 0x0B000000UL,
+    DTS_HD              = 0x0C000000UL,
+    /** IEC61937 is encoded audio wrapped in 16-bit PCM. */
+    IEC61937            = 0x0D000000UL,
+    DOLBY_TRUEHD        = 0x0E000000UL,
+    EVRC                = 0x10000000UL,
+    EVRCB               = 0x11000000UL,
+    EVRCWB              = 0x12000000UL,
+    EVRCNW              = 0x13000000UL,
+    AAC_ADIF            = 0x14000000UL,
+    WMA                 = 0x15000000UL,
+    WMA_PRO             = 0x16000000UL,
+    AMR_WB_PLUS         = 0x17000000UL,
+    MP2                 = 0x18000000UL,
+    QCELP               = 0x19000000UL,
+    DSD                 = 0x1A000000UL,
+    FLAC                = 0x1B000000UL,
+    ALAC                = 0x1C000000UL,
+    APE                 = 0x1D000000UL,
+    AAC_ADTS            = 0x1E000000UL,
+    SBC                 = 0x1F000000UL,
+    APTX                = 0x20000000UL,
+    APTX_HD             = 0x21000000UL,
+    AC4                 = 0x22000000UL,
+    LDAC                = 0x23000000UL,
+    /** Dolby Metadata-enhanced Audio Transmission */
+    MAT                 = 0x24000000UL,
+    /** Deprecated */
+    MAIN_MASK           = 0xFF000000UL,
+    SUB_MASK            = 0x00FFFFFFUL,
+
+    /* Subformats */
+    PCM_SUB_16_BIT        = 0x1, // PCM signed 16 bits
+    PCM_SUB_8_BIT         = 0x2, // PCM unsigned 8 bits
+    PCM_SUB_32_BIT        = 0x3, // PCM signed .31 fixed point
+    PCM_SUB_8_24_BIT      = 0x4, // PCM signed 8.23 fixed point
+    PCM_SUB_FLOAT         = 0x5, // PCM single-precision float pt
+    PCM_SUB_24_BIT_PACKED = 0x6, // PCM signed .23 fix pt (3 bytes)
+
+    MP3_SUB_NONE          = 0x0,
+
+    AMR_SUB_NONE          = 0x0,
+
+    AAC_SUB_MAIN          = 0x1,
+    AAC_SUB_LC            = 0x2,
+    AAC_SUB_SSR           = 0x4,
+    AAC_SUB_LTP           = 0x8,
+    AAC_SUB_HE_V1         = 0x10,
+    AAC_SUB_SCALABLE      = 0x20,
+    AAC_SUB_ERLC          = 0x40,
+    AAC_SUB_LD            = 0x80,
+    AAC_SUB_HE_V2         = 0x100,
+    AAC_SUB_ELD           = 0x200,
+    AAC_SUB_XHE           = 0x300,
+
+    VORBIS_SUB_NONE       = 0x0,
+
+    E_AC3_SUB_JOC         = 0x1,
+
+    MAT_SUB_1_0           = 0x1,
+    MAT_SUB_2_0           = 0x2,
+    MAT_SUB_2_1           = 0x3,
+
+    /* Aliases */
+    /** note != AudioFormat.ENCODING_PCM_16BIT */
+    PCM_16_BIT          = (PCM | PCM_SUB_16_BIT),
+    /** note != AudioFormat.ENCODING_PCM_8BIT */
+    PCM_8_BIT           = (PCM | PCM_SUB_8_BIT),
+    PCM_32_BIT          = (PCM | PCM_SUB_32_BIT),
+    PCM_8_24_BIT        = (PCM | PCM_SUB_8_24_BIT),
+    PCM_FLOAT           = (PCM | PCM_SUB_FLOAT),
+    PCM_24_BIT_PACKED   = (PCM | PCM_SUB_24_BIT_PACKED),
+    AAC_MAIN            = (AAC | AAC_SUB_MAIN),
+    AAC_LC              = (AAC | AAC_SUB_LC),
+    AAC_SSR             = (AAC | AAC_SUB_SSR),
+    AAC_LTP             = (AAC | AAC_SUB_LTP),
+    AAC_HE_V1           = (AAC | AAC_SUB_HE_V1),
+    AAC_SCALABLE        = (AAC | AAC_SUB_SCALABLE),
+    AAC_ERLC            = (AAC | AAC_SUB_ERLC),
+    AAC_LD              = (AAC | AAC_SUB_LD),
+    AAC_HE_V2           = (AAC | AAC_SUB_HE_V2),
+    AAC_ELD             = (AAC | AAC_SUB_ELD),
+    AAC_XHE             = (AAC | AAC_SUB_XHE),
+    AAC_ADTS_MAIN       = (AAC_ADTS | AAC_SUB_MAIN),
+    AAC_ADTS_LC         = (AAC_ADTS | AAC_SUB_LC),
+    AAC_ADTS_SSR        = (AAC_ADTS | AAC_SUB_SSR),
+    AAC_ADTS_LTP        = (AAC_ADTS | AAC_SUB_LTP),
+    AAC_ADTS_HE_V1      = (AAC_ADTS | AAC_SUB_HE_V1),
+    AAC_ADTS_SCALABLE   = (AAC_ADTS | AAC_SUB_SCALABLE),
+    AAC_ADTS_ERLC       = (AAC_ADTS | AAC_SUB_ERLC),
+    AAC_ADTS_LD         = (AAC_ADTS | AAC_SUB_LD),
+    AAC_ADTS_HE_V2      = (AAC_ADTS | AAC_SUB_HE_V2),
+    AAC_ADTS_ELD        = (AAC_ADTS | AAC_SUB_ELD),
+    AAC_ADTS_XHE        = (AAC_ADTS | AAC_SUB_XHE),
+    E_AC3_JOC           = (E_AC3 | E_AC3_SUB_JOC),
+    MAT_1_0             = (MAT | MAT_SUB_1_0),
+    MAT_2_0             = (MAT | MAT_SUB_2_0),
+    MAT_2_1             = (MAT | MAT_SUB_2_1),
+};
+
+/**
+ * Usage of these values highlights places in the code that use 2- or 8- channel
+ * assumptions.
+ */
+@export(name="")
+enum FixedChannelCount : int32_t {
+    FCC_2 = 2, // This is typically due to legacy implementation of stereo I/O
+    FCC_8 = 8  // This is typically due to audio mixer and resampler limitations
+};
+
+/**
+ * A channel mask per se only defines the presence or absence of a channel, not
+ * the order.  See AUDIO_INTERLEAVE_* for the platform convention of order.
+ *
+ * AudioChannelMask is an opaque type and its internal layout should not be
+ * assumed as it may change in the future.  Instead, always use functions
+ * to examine it.
+ *
+ * These are the current representations:
+ *
+ *   REPRESENTATION_POSITION
+ *     is a channel mask representation for position assignment.  Each low-order
+ *     bit corresponds to the spatial position of a transducer (output), or
+ *     interpretation of channel (input).  The user of a channel mask needs to
+ *     know the context of whether it is for output or input.  The constants
+ *     OUT_* or IN_* apply to the bits portion.  It is not permitted for no bits
+ *     to be set.
+ *
+ *   REPRESENTATION_INDEX
+ *     is a channel mask representation for index assignment.  Each low-order
+ *     bit corresponds to a selected channel.  There is no platform
+ *     interpretation of the various bits.  There is no concept of output or
+ *     input.  It is not permitted for no bits to be set.
+ *
+ * All other representations are reserved for future use.
+ *
+ * Warning: current representation distinguishes between input and output, but
+ * this will not the be case in future revisions of the platform. Wherever there
+ * is an ambiguity between input and output that is currently resolved by
+ * checking the channel mask, the implementer should look for ways to fix it
+ * with additional information outside of the mask.
+ */
+@export(name="", value_prefix="AUDIO_CHANNEL_")
+enum AudioChannelMask : uint32_t {
+    /** must be 0 for compatibility */
+    REPRESENTATION_POSITION = 0,
+    /** 1 is reserved for future use */
+    REPRESENTATION_INDEX    = 2,
+    /* 3 is reserved for future use */
+
+    /** These can be a complete value of AudioChannelMask */
+    NONE                      = 0x0,
+    INVALID                   = 0xC0000000,
+
+   /*
+    * These can be the bits portion of an AudioChannelMask
+    * with representation REPRESENTATION_POSITION.
+    */
+
+    /** output channels */
+    OUT_FRONT_LEFT            = 0x1,
+    OUT_FRONT_RIGHT           = 0x2,
+    OUT_FRONT_CENTER          = 0x4,
+    OUT_LOW_FREQUENCY         = 0x8,
+    OUT_BACK_LEFT             = 0x10,
+    OUT_BACK_RIGHT            = 0x20,
+    OUT_FRONT_LEFT_OF_CENTER  = 0x40,
+    OUT_FRONT_RIGHT_OF_CENTER = 0x80,
+    OUT_BACK_CENTER           = 0x100,
+    OUT_SIDE_LEFT             = 0x200,
+    OUT_SIDE_RIGHT            = 0x400,
+    OUT_TOP_CENTER            = 0x800,
+    OUT_TOP_FRONT_LEFT        = 0x1000,
+    OUT_TOP_FRONT_CENTER      = 0x2000,
+    OUT_TOP_FRONT_RIGHT       = 0x4000,
+    OUT_TOP_BACK_LEFT         = 0x8000,
+    OUT_TOP_BACK_CENTER       = 0x10000,
+    OUT_TOP_BACK_RIGHT        = 0x20000,
+    OUT_TOP_CENTER_LEFT       = 0x40000,
+    OUT_TOP_CENTER_RIGHT      = 0x80000,
+
+    OUT_MONO     = OUT_FRONT_LEFT,
+    OUT_STEREO   = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
+    OUT_2POINT1  = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
+    OUT_2POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+                         OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_RIGHT),
+    OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+                         OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_RIGHT |
+                         OUT_LOW_FREQUENCY),
+    OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT |
+                         OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_RIGHT),
+    OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT |
+                        OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_RIGHT |
+                        OUT_LOW_FREQUENCY),
+    OUT_QUAD     = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT),
+    OUT_QUAD_BACK = OUT_QUAD,
+    /** like OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
+    OUT_QUAD_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_SURROUND = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_BACK_CENTER),
+    OUT_PENTA = (OUT_QUAD | OUT_FRONT_CENTER),
+    OUT_5POINT1   = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT),
+    OUT_5POINT1_BACK = OUT_5POINT1,
+    /** like OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
+    OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT |
+            OUT_BACK_CENTER),
+    /** matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND */
+    OUT_7POINT1  = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
+            OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
+            OUT_BACK_LEFT | OUT_BACK_RIGHT |
+            OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+    // Note that the 2.0 OUT_ALL* have been moved to helper functions
+
+    /* These are bits only, not complete values */
+
+    /** input channels */
+    IN_LEFT            = 0x4,
+    IN_RIGHT           = 0x8,
+    IN_FRONT           = 0x10,
+    IN_BACK            = 0x20,
+    IN_LEFT_PROCESSED  = 0x40,
+    IN_RIGHT_PROCESSED = 0x80,
+    IN_FRONT_PROCESSED = 0x100,
+    IN_BACK_PROCESSED  = 0x200,
+    IN_PRESSURE        = 0x400,
+    IN_X_AXIS          = 0x800,
+    IN_Y_AXIS          = 0x1000,
+    IN_Z_AXIS          = 0x2000,
+    IN_BACK_LEFT       = 0x10000,
+    IN_BACK_RIGHT      = 0x20000,
+    IN_CENTER          = 0x40000,
+    IN_LOW_FREQUENCY   = 0x100000,
+    IN_TOP_LEFT        = 0x200000,
+    IN_TOP_RIGHT       = 0x400000,
+
+    IN_VOICE_UPLINK    = 0x4000,
+    IN_VOICE_DNLINK    = 0x8000,
+
+    IN_MONO   = IN_FRONT,
+    IN_STEREO = (IN_LEFT | IN_RIGHT),
+    IN_FRONT_BACK = (IN_FRONT | IN_BACK),
+    IN_6 = (IN_LEFT | IN_RIGHT |
+            IN_FRONT | IN_BACK |
+            IN_LEFT_PROCESSED | IN_RIGHT_PROCESSED),
+    IN_5POINT1 = (IN_LEFT | IN_CENTER | IN_RIGHT |
+                  IN_BACK_LEFT | IN_BACK_RIGHT | IN_LOW_FREQUENCY),
+    IN_VOICE_UPLINK_MONO = (IN_VOICE_UPLINK | IN_MONO),
+    IN_VOICE_DNLINK_MONO = (IN_VOICE_DNLINK | IN_MONO),
+    IN_VOICE_CALL_MONO   = (IN_VOICE_UPLINK_MONO |
+            IN_VOICE_DNLINK_MONO),
+    // Note that the 2.0 IN_ALL* have been moved to helper functions
+
+    COUNT_MAX    = 30,
+    INDEX_HDR    = REPRESENTATION_INDEX << COUNT_MAX,
+    INDEX_MASK_1 = INDEX_HDR | ((1 << 1) - 1),
+    INDEX_MASK_2 = INDEX_HDR | ((1 << 2) - 1),
+    INDEX_MASK_3 = INDEX_HDR | ((1 << 3) - 1),
+    INDEX_MASK_4 = INDEX_HDR | ((1 << 4) - 1),
+    INDEX_MASK_5 = INDEX_HDR | ((1 << 5) - 1),
+    INDEX_MASK_6 = INDEX_HDR | ((1 << 6) - 1),
+    INDEX_MASK_7 = INDEX_HDR | ((1 << 7) - 1),
+    INDEX_MASK_8 = INDEX_HDR | ((1 << 8) - 1)
+};
+
+/**
+ * Major modes for a mobile device. The current mode setting affects audio
+ * routing.
+ */
+@export(name="audio_mode_t", value_prefix="AUDIO_MODE_")
+enum AudioMode : int32_t {
+    NORMAL           = 0,
+    RINGTONE         = 1,
+    /** Calls handled by the telephony stack (Eg: PSTN). */
+    IN_CALL          = 2,
+    /** Calls handled by apps (Eg: Hangout). */
+    IN_COMMUNICATION = 3,
+};
+
+@export(name="", value_prefix="AUDIO_DEVICE_")
+enum AudioDevice : uint64_t {
+    NONE                          = 0x0,
+    /** reserved bits */
+    BIT_IN                        = 0x80000000,
+    BIT_DEFAULT                   = 0x40000000,
+    /** output devices */
+    OUT_EARPIECE                  = 0x1,
+    OUT_SPEAKER                   = 0x2,
+    OUT_WIRED_HEADSET             = 0x4,
+    OUT_WIRED_HEADPHONE           = 0x8,
+    OUT_BLUETOOTH_SCO             = 0x10,
+    OUT_BLUETOOTH_SCO_HEADSET     = 0x20,
+    OUT_BLUETOOTH_SCO_CARKIT      = 0x40,
+    OUT_BLUETOOTH_A2DP            = 0x80,
+    OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
+    OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200,
+    OUT_AUX_DIGITAL               = 0x400,
+    OUT_HDMI                      = OUT_AUX_DIGITAL,
+    /** uses an analog connection (multiplexed over the USB pins for instance) */
+    OUT_ANLG_DOCK_HEADSET         = 0x800,
+    OUT_DGTL_DOCK_HEADSET         = 0x1000,
+    /** USB accessory mode: Android device is USB device and dock is USB host */
+    OUT_USB_ACCESSORY             = 0x2000,
+    /** USB host mode: Android device is USB host and dock is USB device */
+    OUT_USB_DEVICE                = 0x4000,
+    OUT_REMOTE_SUBMIX             = 0x8000,
+    /** Telephony voice TX path */
+    OUT_TELEPHONY_TX              = 0x10000,
+    /** Analog jack with line impedance detected */
+    OUT_LINE                      = 0x20000,
+    /** HDMI Audio Return Channel */
+    OUT_HDMI_ARC                  = 0x40000,
+    /** S/PDIF out */
+    OUT_SPDIF                     = 0x80000,
+    /** FM transmitter out */
+    OUT_FM                        = 0x100000,
+    /** Line out for av devices */
+    OUT_AUX_LINE                  = 0x200000,
+    /** limited-output speaker device for acoustic safety */
+    OUT_SPEAKER_SAFE              = 0x400000,
+    OUT_IP                        = 0x800000,
+    /** audio bus implemented by the audio system (e.g an MOST stereo channel) */
+    OUT_BUS                       = 0x1000000,
+    OUT_PROXY                     = 0x2000000,
+    OUT_USB_HEADSET               = 0x4000000,
+    OUT_ECHO_CANCELLER            = 0x10000000,
+    OUT_DEFAULT                   = BIT_DEFAULT,
+    // Note that the 2.0 OUT_ALL* have been moved to helper functions
+
+    /** input devices */
+    IN_COMMUNICATION         = BIT_IN | 0x1,
+    IN_AMBIENT               = BIT_IN | 0x2,
+    IN_BUILTIN_MIC           = BIT_IN | 0x4,
+    IN_BLUETOOTH_SCO_HEADSET = BIT_IN | 0x8,
+    IN_WIRED_HEADSET         = BIT_IN | 0x10,
+    IN_AUX_DIGITAL           = BIT_IN | 0x20,
+    IN_HDMI                  = IN_AUX_DIGITAL,
+    /** Telephony voice RX path */
+    IN_VOICE_CALL            = BIT_IN | 0x40,
+    IN_TELEPHONY_RX          = IN_VOICE_CALL,
+    IN_BACK_MIC              = BIT_IN | 0x80,
+    IN_REMOTE_SUBMIX         = BIT_IN | 0x100,
+    IN_ANLG_DOCK_HEADSET     = BIT_IN | 0x200,
+    IN_DGTL_DOCK_HEADSET     = BIT_IN | 0x400,
+    IN_USB_ACCESSORY         = BIT_IN | 0x800,
+    IN_USB_DEVICE            = BIT_IN | 0x1000,
+    /** FM tuner input */
+    IN_FM_TUNER              = BIT_IN | 0x2000,
+    /** TV tuner input */
+    IN_TV_TUNER              = BIT_IN | 0x4000,
+    /** Analog jack with line impedance detected */
+    IN_LINE                  = BIT_IN | 0x8000,
+    /** S/PDIF in */
+    IN_SPDIF                 = BIT_IN | 0x10000,
+    IN_BLUETOOTH_A2DP        = BIT_IN | 0x20000,
+    IN_LOOPBACK              = BIT_IN | 0x40000,
+    IN_IP                    = BIT_IN | 0x80000,
+    /** audio bus implemented by the audio system (e.g an MOST stereo channel) */
+    IN_BUS                   = BIT_IN | 0x100000,
+    IN_PROXY                 = BIT_IN | 0x1000000,
+    IN_USB_HEADSET           = BIT_IN | 0x2000000,
+    IN_BLUETOOTH_BLE         = BIT_IN | 0x4000000,
+    IN_DEFAULT               = BIT_IN | BIT_DEFAULT,
+
+    // Note that the 2.0 IN_ALL* have been moved to helper functions
+};
+
+/**
+ * The audio output flags serve two purposes:
+ *
+ *  - when an AudioTrack is created they indicate a "wish" to be connected to an
+ *    output stream with attributes corresponding to the specified flags;
+ *
+ *  - when present in an output profile descriptor listed for a particular audio
+ *    hardware module, they indicate that an output stream can be opened that
+ *    supports the attributes indicated by the flags.
+ *
+ * The audio policy manager will try to match the flags in the request
+ * (when getOuput() is called) to an available output stream.
+ */
+@export(name="audio_output_flags_t", value_prefix="AUDIO_OUTPUT_FLAG_")
+enum AudioOutputFlag : int32_t {
+    NONE    = 0x0, // no attributes
+    DIRECT  = 0x1, // this output directly connects a track
+                   // to one output stream: no software mixer
+    PRIMARY = 0x2, // this output is the primary output of the device. It is
+                   // unique and must be present. It is opened by default and
+                   // receives routing, audio mode and volume controls related
+                   // to voice calls.
+    FAST    = 0x4,    // output supports "fast tracks", defined elsewhere
+    DEEP_BUFFER      = 0x8,   // use deep audio buffers
+    COMPRESS_OFFLOAD = 0x10,  // offload playback of compressed streams to
+                              // hardware codec
+    NON_BLOCKING     = 0x20,  // use non-blocking write
+    HW_AV_SYNC = 0x40,   // output uses a hardware A/V sync
+    TTS        = 0x80,   // output for streams transmitted through speaker at a
+                         // sample rate high enough to accommodate lower-range
+                         // ultrasonic p/b
+    RAW        = 0x100,  // minimize signal processing
+    SYNC       = 0x200,  // synchronize I/O streams
+    IEC958_NONAUDIO = 0x400, // Audio stream contains compressed audio in SPDIF
+                             // data bursts, not PCM.
+    DIRECT_PCM = 0x2000,     // Audio stream containing PCM data that needs
+                             // to pass through compress path for DSP post proc.
+    MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode.
+    VOIP_RX = 0x8000,    // preferred output for VoIP calls.
+    /** preferred output for call music */
+    INCALL_MUSIC = 0x10000,
+};
+
+/**
+ * The audio input flags are analogous to audio output flags.
+ * Currently they are used only when an AudioRecord is created,
+ * to indicate a preference to be connected to an input stream with
+ * attributes corresponding to the specified flags.
+ */
+@export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_")
+enum AudioInputFlag : int32_t {
+    NONE         = 0x0,  // no attributes
+    FAST         = 0x1,  // prefer an input that supports "fast tracks"
+    HW_HOTWORD   = 0x2,  // prefer an input that captures from hw hotword source
+    RAW          = 0x4,  // minimize signal processing
+    SYNC         = 0x8,  // synchronize I/O streams
+    MMAP_NOIRQ   = 0x10, // input operates in MMAP no IRQ mode.
+    VOIP_TX      = 0x20, // preferred input for VoIP calls.
+    HW_AV_SYNC   = 0x40, // input connected to an output that uses a hardware A/V sync
+};
+
+@export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
+enum AudioUsage : int32_t {
+    // These values must kept in sync with
+    //  frameworks/base/media/java/android/media/AudioAttributes.java
+    // Note that not all framework values are exposed
+    UNKNOWN                            = 0,
+    MEDIA                              = 1,
+    VOICE_COMMUNICATION                = 2,
+    VOICE_COMMUNICATION_SIGNALLING     = 3,
+    ALARM                              = 4,
+    NOTIFICATION                       = 5,
+    NOTIFICATION_TELEPHONY_RINGTONE    = 6,
+    ASSISTANCE_ACCESSIBILITY           = 11,
+    ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
+    ASSISTANCE_SONIFICATION            = 13,
+    GAME                               = 14,
+    VIRTUAL_SOURCE                     = 15,
+    ASSISTANT                          = 16,
+};
+
+/** Type of audio generated by an application. */
+@export(name="audio_content_type_t", value_prefix="AUDIO_CONTENT_TYPE_")
+enum AudioContentType : uint32_t {
+    UNKNOWN      = 0,
+    SPEECH       = 1,
+    MUSIC        = 2,
+    MOVIE        = 3,
+    SONIFICATION = 4,
+};
+
+/**
+ * Additional information about the stream passed to hardware decoders.
+ */
+struct AudioOffloadInfo {
+    uint32_t sampleRateHz;
+    bitfield<AudioChannelMask> channelMask;
+    AudioFormat format;
+    AudioStreamType streamType;
+    uint32_t bitRatePerSecond;
+    int64_t durationMicroseconds;  // -1 if unknown
+    bool hasVideo;
+    bool isStreaming;
+    uint32_t bitWidth;
+    uint32_t bufferSize;
+    AudioUsage usage;
+};
+
+/**
+ * Commonly used audio stream configuration parameters.
+ */
+struct AudioConfig {
+    uint32_t sampleRateHz;
+    bitfield<AudioChannelMask> channelMask;
+    AudioFormat format;
+    AudioOffloadInfo offloadInfo;
+    uint64_t frameCount;
+};
+
+
+/*
+ *
+ *  Volume control
+ *
+ */
+
+/**
+ * Type of gain control exposed by an audio port.
+ */
+@export(name="", value_prefix="AUDIO_GAIN_MODE_")
+enum AudioGainMode : uint32_t {
+    JOINT = 0x1,    // supports joint channel gain control
+    CHANNELS = 0x2, // supports separate channel gain control
+    RAMP = 0x4      // supports gain ramps
+};
+
+/**
+ * An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port.
+ */
+struct AudioGain {
+    bitfield<AudioGainMode> mode;
+    bitfield<AudioChannelMask> channelMask; // channels which gain an be controlled
+    int32_t minValue;     // minimum gain value in millibels
+    int32_t maxValue;     // maximum gain value in millibels
+    int32_t defaultValue; // default gain value in millibels
+    uint32_t stepValue;   // gain step in millibels
+    uint32_t minRampMs;   // minimum ramp duration in ms
+    uint32_t maxRampMs;   // maximum ramp duration in ms
+};
+
+/**
+ * The gain configuration structure is used to get or set the gain values of a
+ * given port.
+ */
+struct AudioGainConfig {
+    int32_t index;  // index of the corresponding AudioGain in AudioPort.gains
+    AudioGainMode mode;
+    AudioChannelMask channelMask;  // channels which gain value follows
+    /**
+     * 4 = sizeof(AudioChannelMask),
+     * 8 is not "FCC_8", so it won't need to be changed for > 8 channels.
+     * Gain values in millibels for each channel ordered from LSb to MSb in
+     * channel mask. The number of values is 1 in joint mode or
+     * popcount(channel_mask).
+     */
+    int32_t[4 * 8] values;
+    uint32_t rampDurationMs;  // ramp duration in ms
+};
+
+
+/*
+ *
+ *  Routing control
+ *
+ */
+
+/*
+ * Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * the interface.
+ */
+
+/** Audio port role: either source or sink */
+@export(name="audio_port_role_t", value_prefix="AUDIO_PORT_ROLE_")
+enum AudioPortRole : int32_t {
+    NONE,
+    SOURCE,
+    SINK,
+};
+
+/**
+ * Audio port type indicates if it is a session (e.g AudioTrack), a mix (e.g
+ * PlaybackThread output) or a physical device (e.g OUT_SPEAKER)
+ */
+@export(name="audio_port_type_t", value_prefix="AUDIO_PORT_TYPE_")
+enum AudioPortType : int32_t {
+    NONE,
+    DEVICE,
+    MIX,
+    SESSION,
+};
+
+/**
+ * Extension for audio port configuration structure when the audio port is a
+ * hardware device.
+ */
+struct AudioPortConfigDeviceExt {
+    AudioModuleHandle hwModule;  // module the device is attached to
+    AudioDevice type;            // device type (e.g OUT_SPEAKER)
+    uint8_t[32] address;         // device address. "" if N/A
+};
+
+/**
+ * Extension for audio port configuration structure when the audio port is an
+ * audio session.
+ */
+struct AudioPortConfigSessionExt {
+    AudioSession session;
+};
+
+/**
+ * Flags indicating which fields are to be considered in AudioPortConfig.
+ */
+@export(name="", value_prefix="AUDIO_PORT_CONFIG_")
+enum AudioPortConfigMask : uint32_t {
+    SAMPLE_RATE = 0x1,
+    CHANNEL_MASK =  0x2,
+    FORMAT = 0x4,
+    GAIN = 0x8,
+};
+
+/**
+ * Audio port configuration structure used to specify a particular configuration
+ * of an audio port.
+ */
+struct AudioPortConfig {
+    AudioPortHandle id;
+    bitfield<AudioPortConfigMask> configMask;
+    uint32_t sampleRateHz;
+    bitfield<AudioChannelMask> channelMask;
+    AudioFormat format;
+    AudioGainConfig gain;
+    AudioPortType type;  // type is used as a discriminator for Ext union
+    AudioPortRole role;  // role is used as a discriminator for UseCase union
+    union Ext {
+        AudioPortConfigDeviceExt device;
+        struct AudioPortConfigMixExt {
+            AudioModuleHandle hwModule; // module the stream is attached to
+            AudioIoHandle ioHandle;     // I/O handle of the input/output stream
+            union UseCase {
+                AudioStreamType stream;
+                AudioSource source;
+            } useCase;
+        } mix;
+        AudioPortConfigSessionExt session;
+    } ext;
+};
+
+/**
+ * Extension for audio port structure when the audio port is a hardware device.
+ */
+struct AudioPortDeviceExt {
+    AudioModuleHandle hwModule;    // module the device is attached to
+    AudioDevice type;
+    /** 32 byte string identifying the port. */
+    uint8_t[32] address;
+};
+
+/**
+ * Latency class of the audio mix.
+ */
+@export(name="audio_mix_latency_class_t", value_prefix="AUDIO_LATENCY_")
+enum AudioMixLatencyClass : int32_t {
+    LOW,
+    NORMAL
+};
+
+struct AudioPortMixExt {
+    AudioModuleHandle hwModule;     // module the stream is attached to
+    AudioIoHandle ioHandle;         // I/O handle of the stream
+    AudioMixLatencyClass latencyClass;
+};
+
+/**
+ * Extension for audio port structure when the audio port is an audio session.
+ */
+struct AudioPortSessionExt {
+    AudioSession session;
+};
+
+struct AudioPort {
+    AudioPortHandle id;
+    AudioPortRole role;
+    string name;
+    vec<uint32_t> sampleRates;
+    vec<bitfield<AudioChannelMask>> channelMasks;
+    vec<AudioFormat> formats;
+    vec<AudioGain> gains;
+    AudioPortConfig activeConfig; // current audio port configuration
+    AudioPortType type;  // type is used as a discriminator
+    union Ext {
+        AudioPortDeviceExt device;
+        AudioPortMixExt mix;
+        AudioPortSessionExt session;
+    } ext;
+};
+
+struct ThreadInfo {
+    int64_t pid;
+    int64_t tid;
+};
diff --git a/audio/common/README b/audio/common/README
new file mode 100644
index 0000000..cd03106
--- /dev/null
+++ b/audio/common/README
@@ -0,0 +1 @@
+This folder contains code common to audio core and effect API
diff --git a/audio/common/2.0/default/OWNERS b/audio/common/all-versions/OWNERS
similarity index 100%
copy from audio/common/2.0/default/OWNERS
copy to audio/common/all-versions/OWNERS
diff --git a/audio/common/all-versions/README b/audio/common/all-versions/README
new file mode 100644
index 0000000..d8df022
--- /dev/null
+++ b/audio/common/all-versions/README
@@ -0,0 +1 @@
+This folder contains code common to all versions of the audio API
diff --git a/audio/common/all-versions/default/Android.bp b/audio/common/all-versions/default/Android.bp
new file mode 100644
index 0000000..8f6b74c
--- /dev/null
+++ b/audio/common/all-versions/default/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "android.hardware.audio.common-util",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "EffectMap.cpp",
+    ],
+
+    export_include_dirs: ["include"],
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libhidlbase",
+    ],
+
+    header_libs: [
+        "libaudio_system_headers",
+        "libhardware_headers",
+    ],
+}
diff --git a/audio/common/all-versions/default/EffectMap.cpp b/audio/common/all-versions/default/EffectMap.cpp
new file mode 100644
index 0000000..7f8da1e
--- /dev/null
+++ b/audio/common/all-versions/default/EffectMap.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#include <atomic>
+
+#include "common/all-versions/default/EffectMap.h"
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(EffectMap);
+
+// static
+const uint64_t EffectMap::INVALID_ID = 0;
+
+// static
+uint64_t EffectMap::makeUniqueId() {
+    static std::atomic<uint64_t> counter{INVALID_ID + 1};
+    return counter++;
+}
+
+uint64_t EffectMap::add(effect_handle_t handle) {
+    uint64_t newId = makeUniqueId();
+    std::lock_guard<std::mutex> lock(mLock);
+    mEffects.add(newId, handle);
+    return newId;
+}
+
+effect_handle_t EffectMap::get(const uint64_t& id) {
+    std::lock_guard<std::mutex> lock(mLock);
+    ssize_t idx = mEffects.indexOfKey(id);
+    return idx >= 0 ? mEffects[idx] : NULL;
+}
+
+void EffectMap::remove(effect_handle_t handle) {
+    std::lock_guard<std::mutex> lock(mLock);
+    for (size_t i = 0; i < mEffects.size(); ++i) {
+        if (mEffects[i] == handle) {
+            mEffects.removeItemsAt(i);
+            break;
+        }
+    }
+}
+
+}  // namespace android
diff --git a/audio/common/all-versions/default/include/common/all-versions/default/EffectMap.h b/audio/common/all-versions/default/include/common/all-versions/default/EffectMap.h
new file mode 100644
index 0000000..547c6d5
--- /dev/null
+++ b/audio/common/all-versions/default/include/common/all-versions/default/EffectMap.h
@@ -0,0 +1,46 @@
+/*
+ * 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_audio_common_EffectMap_H_
+#define android_hardware_audio_common_EffectMap_H_
+
+#include <mutex>
+
+#include <hardware/audio_effect.h>
+#include <utils/KeyedVector.h>
+#include <utils/Singleton.h>
+
+namespace android {
+
+// This class needs to be in 'android' ns because Singleton macros require that.
+class EffectMap : public Singleton<EffectMap> {
+   public:
+    static const uint64_t INVALID_ID;
+
+    uint64_t add(effect_handle_t handle);
+    effect_handle_t get(const uint64_t& id);
+    void remove(effect_handle_t handle);
+
+   private:
+    static uint64_t makeUniqueId();
+
+    std::mutex mLock;
+    KeyedVector<uint64_t, effect_handle_t> mEffects;
+};
+
+}  // namespace android
+
+#endif  // android_hardware_audio_common_EffectMap_H_
diff --git a/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.h b/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.h
new file mode 100644
index 0000000..1654ac6
--- /dev/null
+++ b/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.h
@@ -0,0 +1,73 @@
+/*
+ * 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 AUDIO_HAL_VERSION
+#error "AUDIO_HAL_VERSION must be set before including this file."
+#endif
+
+#include <memory>
+
+#include <system/audio.h>
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioConfig;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioGain;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioGainConfig;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioOffloadInfo;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPort;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortConfig;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::Uuid;
+using ::android::hardware::hidl_vec;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace AUDIO_HAL_VERSION {
+
+class HidlUtils {
+   public:
+    static void audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config);
+    static void audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig);
+    static void audioGainConfigFromHal(const struct audio_gain_config& halConfig,
+                                       AudioGainConfig* config);
+    static void audioGainConfigToHal(const AudioGainConfig& config,
+                                     struct audio_gain_config* halConfig);
+    static void audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain);
+    static void audioGainToHal(const AudioGain& gain, struct audio_gain* halGain);
+    static void audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
+                                        AudioOffloadInfo* offload);
+    static void audioOffloadInfoToHal(const AudioOffloadInfo& offload,
+                                      audio_offload_info_t* halOffload);
+    static void audioPortConfigFromHal(const struct audio_port_config& halConfig,
+                                       AudioPortConfig* config);
+    static void audioPortConfigToHal(const AudioPortConfig& config,
+                                     struct audio_port_config* halConfig);
+    static void audioPortConfigsFromHal(unsigned int numHalConfigs,
+                                        const struct audio_port_config* halConfigs,
+                                        hidl_vec<AudioPortConfig>* configs);
+    static std::unique_ptr<audio_port_config[]> audioPortConfigsToHal(
+        const hidl_vec<AudioPortConfig>& configs);
+    static void audioPortFromHal(const struct audio_port& halPort, AudioPort* port);
+    static void audioPortToHal(const AudioPort& port, struct audio_port* halPort);
+    static void uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid);
+    static void uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid);
+};
+
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h b/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h
new file mode 100644
index 0000000..935f307
--- /dev/null
+++ b/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h
@@ -0,0 +1,346 @@
+/*
+ * 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 AUDIO_HAL_VERSION
+#error "AUDIO_HAL_VERSION must be set before including this file."
+#endif
+
+#include <string.h>
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioFormat;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioGainMode;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMixLatencyClass;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortConfigMask;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortRole;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortType;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioStreamType;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioUsage;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace AUDIO_HAL_VERSION {
+
+void HidlUtils::audioConfigFromHal(const audio_config_t& halConfig, AudioConfig* config) {
+    config->sampleRateHz = halConfig.sample_rate;
+    config->channelMask = AudioChannelMask(halConfig.channel_mask);
+    config->format = AudioFormat(halConfig.format);
+    audioOffloadInfoFromHal(halConfig.offload_info, &config->offloadInfo);
+    config->frameCount = halConfig.frame_count;
+}
+
+void HidlUtils::audioConfigToHal(const AudioConfig& config, audio_config_t* halConfig) {
+    memset(halConfig, 0, sizeof(audio_config_t));
+    halConfig->sample_rate = config.sampleRateHz;
+    halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
+    halConfig->format = static_cast<audio_format_t>(config.format);
+    audioOffloadInfoToHal(config.offloadInfo, &halConfig->offload_info);
+    halConfig->frame_count = config.frameCount;
+}
+
+void HidlUtils::audioGainConfigFromHal(const struct audio_gain_config& halConfig,
+                                       AudioGainConfig* config) {
+    config->index = halConfig.index;
+    config->mode = AudioGainMode(halConfig.mode);
+    config->channelMask = AudioChannelMask(halConfig.channel_mask);
+    for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) {
+        config->values[i] = halConfig.values[i];
+    }
+    config->rampDurationMs = halConfig.ramp_duration_ms;
+}
+
+void HidlUtils::audioGainConfigToHal(const AudioGainConfig& config,
+                                     struct audio_gain_config* halConfig) {
+    halConfig->index = config.index;
+    halConfig->mode = static_cast<audio_gain_mode_t>(config.mode);
+    halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
+    memset(halConfig->values, 0, sizeof(halConfig->values));
+    for (size_t i = 0; i < sizeof(audio_channel_mask_t) * 8; ++i) {
+        halConfig->values[i] = config.values[i];
+    }
+    halConfig->ramp_duration_ms = config.rampDurationMs;
+}
+
+void HidlUtils::audioGainFromHal(const struct audio_gain& halGain, AudioGain* gain) {
+    gain->mode = AudioGainMode(halGain.mode);
+    gain->channelMask = AudioChannelMask(halGain.channel_mask);
+    gain->minValue = halGain.min_value;
+    gain->maxValue = halGain.max_value;
+    gain->defaultValue = halGain.default_value;
+    gain->stepValue = halGain.step_value;
+    gain->minRampMs = halGain.min_ramp_ms;
+    gain->maxRampMs = halGain.max_ramp_ms;
+}
+
+void HidlUtils::audioGainToHal(const AudioGain& gain, struct audio_gain* halGain) {
+    halGain->mode = static_cast<audio_gain_mode_t>(gain.mode);
+    halGain->channel_mask = static_cast<audio_channel_mask_t>(gain.channelMask);
+    halGain->min_value = gain.minValue;
+    halGain->max_value = gain.maxValue;
+    halGain->default_value = gain.defaultValue;
+    halGain->step_value = gain.stepValue;
+    halGain->min_ramp_ms = gain.minRampMs;
+    halGain->max_ramp_ms = gain.maxRampMs;
+}
+
+void HidlUtils::audioOffloadInfoFromHal(const audio_offload_info_t& halOffload,
+                                        AudioOffloadInfo* offload) {
+    offload->sampleRateHz = halOffload.sample_rate;
+    offload->channelMask = AudioChannelMask(halOffload.channel_mask);
+    offload->format = AudioFormat(halOffload.format);
+    offload->streamType = AudioStreamType(halOffload.stream_type);
+    offload->bitRatePerSecond = halOffload.bit_rate;
+    offload->durationMicroseconds = halOffload.duration_us;
+    offload->hasVideo = halOffload.has_video;
+    offload->isStreaming = halOffload.is_streaming;
+    offload->bitWidth = halOffload.bit_width;
+    offload->bufferSize = halOffload.offload_buffer_size;
+    offload->usage = static_cast<AudioUsage>(halOffload.usage);
+}
+
+void HidlUtils::audioOffloadInfoToHal(const AudioOffloadInfo& offload,
+                                      audio_offload_info_t* halOffload) {
+    *halOffload = AUDIO_INFO_INITIALIZER;
+    halOffload->sample_rate = offload.sampleRateHz;
+    halOffload->channel_mask = static_cast<audio_channel_mask_t>(offload.channelMask);
+    halOffload->format = static_cast<audio_format_t>(offload.format);
+    halOffload->stream_type = static_cast<audio_stream_type_t>(offload.streamType);
+    halOffload->bit_rate = offload.bitRatePerSecond;
+    halOffload->duration_us = offload.durationMicroseconds;
+    halOffload->has_video = offload.hasVideo;
+    halOffload->is_streaming = offload.isStreaming;
+    halOffload->bit_width = offload.bitWidth;
+    halOffload->offload_buffer_size = offload.bufferSize;
+    halOffload->usage = static_cast<audio_usage_t>(offload.usage);
+}
+
+void HidlUtils::audioPortConfigFromHal(const struct audio_port_config& halConfig,
+                                       AudioPortConfig* config) {
+    config->id = halConfig.id;
+    config->role = AudioPortRole(halConfig.role);
+    config->type = AudioPortType(halConfig.type);
+    config->configMask = AudioPortConfigMask(halConfig.config_mask);
+    config->sampleRateHz = halConfig.sample_rate;
+    config->channelMask = AudioChannelMask(halConfig.channel_mask);
+    config->format = AudioFormat(halConfig.format);
+    audioGainConfigFromHal(halConfig.gain, &config->gain);
+    switch (halConfig.type) {
+        case AUDIO_PORT_TYPE_NONE:
+            break;
+        case AUDIO_PORT_TYPE_DEVICE: {
+            config->ext.device.hwModule = halConfig.ext.device.hw_module;
+            config->ext.device.type = AudioDevice(halConfig.ext.device.type);
+            memcpy(config->ext.device.address.data(), halConfig.ext.device.address,
+                   AUDIO_DEVICE_MAX_ADDRESS_LEN);
+            break;
+        }
+        case AUDIO_PORT_TYPE_MIX: {
+            config->ext.mix.hwModule = halConfig.ext.mix.hw_module;
+            config->ext.mix.ioHandle = halConfig.ext.mix.handle;
+            if (halConfig.role == AUDIO_PORT_ROLE_SOURCE) {
+                config->ext.mix.useCase.source = AudioSource(halConfig.ext.mix.usecase.source);
+            } else if (halConfig.role == AUDIO_PORT_ROLE_SINK) {
+                config->ext.mix.useCase.stream = AudioStreamType(halConfig.ext.mix.usecase.stream);
+            }
+            break;
+        }
+        case AUDIO_PORT_TYPE_SESSION: {
+            config->ext.session.session = halConfig.ext.session.session;
+            break;
+        }
+    }
+}
+
+void HidlUtils::audioPortConfigToHal(const AudioPortConfig& config,
+                                     struct audio_port_config* halConfig) {
+    memset(halConfig, 0, sizeof(audio_port_config));
+    halConfig->id = config.id;
+    halConfig->role = static_cast<audio_port_role_t>(config.role);
+    halConfig->type = static_cast<audio_port_type_t>(config.type);
+    halConfig->config_mask = static_cast<unsigned int>(config.configMask);
+    halConfig->sample_rate = config.sampleRateHz;
+    halConfig->channel_mask = static_cast<audio_channel_mask_t>(config.channelMask);
+    halConfig->format = static_cast<audio_format_t>(config.format);
+    audioGainConfigToHal(config.gain, &halConfig->gain);
+    switch (config.type) {
+        case AudioPortType::NONE:
+            break;
+        case AudioPortType::DEVICE: {
+            halConfig->ext.device.hw_module = config.ext.device.hwModule;
+            halConfig->ext.device.type = static_cast<audio_devices_t>(config.ext.device.type);
+            memcpy(halConfig->ext.device.address, config.ext.device.address.data(),
+                   AUDIO_DEVICE_MAX_ADDRESS_LEN);
+            break;
+        }
+        case AudioPortType::MIX: {
+            halConfig->ext.mix.hw_module = config.ext.mix.hwModule;
+            halConfig->ext.mix.handle = config.ext.mix.ioHandle;
+            if (config.role == AudioPortRole::SOURCE) {
+                halConfig->ext.mix.usecase.source =
+                    static_cast<audio_source_t>(config.ext.mix.useCase.source);
+            } else if (config.role == AudioPortRole::SINK) {
+                halConfig->ext.mix.usecase.stream =
+                    static_cast<audio_stream_type_t>(config.ext.mix.useCase.stream);
+            }
+            break;
+        }
+        case AudioPortType::SESSION: {
+            halConfig->ext.session.session =
+                static_cast<audio_session_t>(config.ext.session.session);
+            break;
+        }
+    }
+}
+
+void HidlUtils::audioPortConfigsFromHal(unsigned int numHalConfigs,
+                                        const struct audio_port_config* halConfigs,
+                                        hidl_vec<AudioPortConfig>* configs) {
+    configs->resize(numHalConfigs);
+    for (unsigned int i = 0; i < numHalConfigs; ++i) {
+        audioPortConfigFromHal(halConfigs[i], &(*configs)[i]);
+    }
+}
+
+std::unique_ptr<audio_port_config[]> HidlUtils::audioPortConfigsToHal(
+    const hidl_vec<AudioPortConfig>& configs) {
+    std::unique_ptr<audio_port_config[]> halConfigs(new audio_port_config[configs.size()]);
+    for (size_t i = 0; i < configs.size(); ++i) {
+        audioPortConfigToHal(configs[i], &halConfigs[i]);
+    }
+    return halConfigs;
+}
+
+void HidlUtils::audioPortFromHal(const struct audio_port& halPort, AudioPort* port) {
+    port->id = halPort.id;
+    port->role = AudioPortRole(halPort.role);
+    port->type = AudioPortType(halPort.type);
+    port->name.setToExternal(halPort.name, strlen(halPort.name));
+    port->sampleRates.resize(halPort.num_sample_rates);
+    for (size_t i = 0; i < halPort.num_sample_rates; ++i) {
+        port->sampleRates[i] = halPort.sample_rates[i];
+    }
+    port->channelMasks.resize(halPort.num_channel_masks);
+    for (size_t i = 0; i < halPort.num_channel_masks; ++i) {
+        port->channelMasks[i] = AudioChannelMask(halPort.channel_masks[i]);
+    }
+    port->formats.resize(halPort.num_formats);
+    for (size_t i = 0; i < halPort.num_formats; ++i) {
+        port->formats[i] = AudioFormat(halPort.formats[i]);
+    }
+    port->gains.resize(halPort.num_gains);
+    for (size_t i = 0; i < halPort.num_gains; ++i) {
+        audioGainFromHal(halPort.gains[i], &port->gains[i]);
+    }
+    audioPortConfigFromHal(halPort.active_config, &port->activeConfig);
+    switch (halPort.type) {
+        case AUDIO_PORT_TYPE_NONE:
+            break;
+        case AUDIO_PORT_TYPE_DEVICE: {
+            port->ext.device.hwModule = halPort.ext.device.hw_module;
+            port->ext.device.type = AudioDevice(halPort.ext.device.type);
+            memcpy(port->ext.device.address.data(), halPort.ext.device.address,
+                   AUDIO_DEVICE_MAX_ADDRESS_LEN);
+            break;
+        }
+        case AUDIO_PORT_TYPE_MIX: {
+            port->ext.mix.hwModule = halPort.ext.mix.hw_module;
+            port->ext.mix.ioHandle = halPort.ext.mix.handle;
+            port->ext.mix.latencyClass = AudioMixLatencyClass(halPort.ext.mix.latency_class);
+            break;
+        }
+        case AUDIO_PORT_TYPE_SESSION: {
+            port->ext.session.session = halPort.ext.session.session;
+            break;
+        }
+    }
+}
+
+void HidlUtils::audioPortToHal(const AudioPort& port, struct audio_port* halPort) {
+    memset(halPort, 0, sizeof(audio_port));
+    halPort->id = port.id;
+    halPort->role = static_cast<audio_port_role_t>(port.role);
+    halPort->type = static_cast<audio_port_type_t>(port.type);
+    memcpy(halPort->name, port.name.c_str(),
+           std::min(port.name.size(), static_cast<size_t>(AUDIO_PORT_MAX_NAME_LEN)));
+    halPort->num_sample_rates =
+        std::min(port.sampleRates.size(), static_cast<size_t>(AUDIO_PORT_MAX_SAMPLING_RATES));
+    for (size_t i = 0; i < halPort->num_sample_rates; ++i) {
+        halPort->sample_rates[i] = port.sampleRates[i];
+    }
+    halPort->num_channel_masks =
+        std::min(port.channelMasks.size(), static_cast<size_t>(AUDIO_PORT_MAX_CHANNEL_MASKS));
+    for (size_t i = 0; i < halPort->num_channel_masks; ++i) {
+        halPort->channel_masks[i] = static_cast<audio_channel_mask_t>(port.channelMasks[i]);
+    }
+    halPort->num_formats =
+        std::min(port.formats.size(), static_cast<size_t>(AUDIO_PORT_MAX_FORMATS));
+    for (size_t i = 0; i < halPort->num_formats; ++i) {
+        halPort->formats[i] = static_cast<audio_format_t>(port.formats[i]);
+    }
+    halPort->num_gains = std::min(port.gains.size(), static_cast<size_t>(AUDIO_PORT_MAX_GAINS));
+    for (size_t i = 0; i < halPort->num_gains; ++i) {
+        audioGainToHal(port.gains[i], &halPort->gains[i]);
+    }
+    audioPortConfigToHal(port.activeConfig, &halPort->active_config);
+    switch (port.type) {
+        case AudioPortType::NONE:
+            break;
+        case AudioPortType::DEVICE: {
+            halPort->ext.device.hw_module = port.ext.device.hwModule;
+            halPort->ext.device.type = static_cast<audio_devices_t>(port.ext.device.type);
+            memcpy(halPort->ext.device.address, port.ext.device.address.data(),
+                   AUDIO_DEVICE_MAX_ADDRESS_LEN);
+            break;
+        }
+        case AudioPortType::MIX: {
+            halPort->ext.mix.hw_module = port.ext.mix.hwModule;
+            halPort->ext.mix.handle = port.ext.mix.ioHandle;
+            halPort->ext.mix.latency_class =
+                static_cast<audio_mix_latency_class_t>(port.ext.mix.latencyClass);
+            break;
+        }
+        case AudioPortType::SESSION: {
+            halPort->ext.session.session = static_cast<audio_session_t>(port.ext.session.session);
+            break;
+        }
+    }
+}
+
+void HidlUtils::uuidFromHal(const audio_uuid_t& halUuid, Uuid* uuid) {
+    uuid->timeLow = halUuid.timeLow;
+    uuid->timeMid = halUuid.timeMid;
+    uuid->versionAndTimeHigh = halUuid.timeHiAndVersion;
+    uuid->variantAndClockSeqHigh = halUuid.clockSeq;
+    memcpy(uuid->node.data(), halUuid.node, uuid->node.size());
+}
+
+void HidlUtils::uuidToHal(const Uuid& uuid, audio_uuid_t* halUuid) {
+    halUuid->timeLow = uuid.timeLow;
+    halUuid->timeMid = uuid.timeMid;
+    halUuid->timeHiAndVersion = uuid.versionAndTimeHigh;
+    halUuid->clockSeq = uuid.variantAndClockSeqHigh;
+    memcpy(halUuid->node, uuid.node.data(), uuid.node.size());
+}
+
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/common/all-versions/test/OWNERS b/audio/common/all-versions/test/OWNERS
new file mode 100644
index 0000000..6a26ae7
--- /dev/null
+++ b/audio/common/all-versions/test/OWNERS
@@ -0,0 +1,2 @@
+yim@google.com
+zhuoyao@google.com
diff --git a/audio/common/test/utility/Android.bp b/audio/common/all-versions/test/utility/Android.bp
similarity index 100%
rename from audio/common/test/utility/Android.bp
rename to audio/common/all-versions/test/utility/Android.bp
diff --git a/audio/common/all-versions/test/utility/include/utility/AssertOk.h b/audio/common/all-versions/test/utility/include/utility/AssertOk.h
new file mode 100644
index 0000000..11e1c24
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/AssertOk.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ASSERTOK_H
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ASSERTOK_H
+
+#include <algorithm>
+#include <initializer_list>
+
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+namespace detail {
+
+// This is a detail namespace, thus it is OK to import a class as nobody else is
+// allowed to use it
+using ::android::hardware::Return;
+
+template <class T>
+inline ::testing::AssertionResult assertIsOk(const char* expr, const Return<T>& ret) {
+    return ::testing::AssertionResult(ret.isOk())
+           << "Expected: " << expr << "\n to be an OK Return but it is not: " << ret.description();
+}
+
+// Call continuation if the provided result isOk
+template <class T, class Continuation>
+inline ::testing::AssertionResult continueIfIsOk(const char* expr, const Return<T>& ret,
+                                                 Continuation continuation) {
+    auto isOkStatus = assertIsOk(expr, ret);
+    return !isOkStatus ? isOkStatus : continuation();
+}
+
+// Expect two equal Results
+template <class Result>
+inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
+                                               Result expected, Result result) {
+    return ::testing::AssertionResult(expected == result)
+           << "Value of: " << r_expr << "\n  Actual: " << ::testing::PrintToString(result)
+           << "\nExpected: " << e_expr << "\nWhich is: " << ::testing::PrintToString(expected);
+}
+
+// Expect two equal Results one being wrapped in an OK Return
+template <class Result>
+inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
+                                               Result expected, const Return<Result>& ret) {
+    return continueIfIsOk(r_expr, ret,
+                          [&] { return assertResult(e_expr, r_expr, expected, Result{ret}); });
+}
+
+// Expect a Result to be part of a list of Results
+template <class Result>
+inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
+                                               const std::initializer_list<Result>& expected,
+                                               Result result) {
+    if (std::find(expected.begin(), expected.end(), result) != expected.end()) {
+        return ::testing::AssertionSuccess();  // result is in expected
+    }
+    return ::testing::AssertionFailure()
+           << "Value of: " << r_expr << "\n  Actual: " << ::testing::PrintToString(result)
+           << "\nExpected one of: " << e_expr
+           << "\n       Which is: " << ::testing::PrintToString(expected);
+}
+
+// Expect a Result wrapped in an OK Return to be part of a list of Results
+template <class Result>
+inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
+                                               const std::initializer_list<Result>& expected,
+                                               const Return<Result>& ret) {
+    return continueIfIsOk(r_expr, ret,
+                          [&] { return assertResult(e_expr, r_expr, expected, Result{ret}); });
+}
+
+inline ::testing::AssertionResult assertOk(const char* expr, const Return<void>& ret) {
+    return assertIsOk(expr, ret);
+}
+
+template <class Result>
+inline ::testing::AssertionResult assertOk(const char* expr, Result result) {
+    return ::testing::AssertionResult(result == Result::OK)
+           << "Expected success: " << expr << "\nActual: " << ::testing::PrintToString(result);
+}
+
+template <class Result>
+inline ::testing::AssertionResult assertOk(const char* expr, const Return<Result>& ret) {
+    return continueIfIsOk(expr, ret, [&] { return assertOk(expr, Result{ret}); });
+}
+}  // namespace detail
+
+#define ASSERT_IS_OK(ret) ASSERT_PRED_FORMAT1(detail::assertIsOk, ret)
+#define EXPECT_IS_OK(ret) EXPECT_PRED_FORMAT1(detail::assertIsOk, ret)
+
+// Test anything provided is and contains only OK
+#define ASSERT_OK(ret) ASSERT_PRED_FORMAT1(detail::assertOk, ret)
+#define EXPECT_OK(ret) EXPECT_PRED_FORMAT1(detail::assertOk, ret)
+
+#define ASSERT_RESULT(expected, ret) ASSERT_PRED_FORMAT2(detail::assertResult, expected, ret)
+#define EXPECT_RESULT(expected, ret) EXPECT_PRED_FORMAT2(detail::assertResult, expected, ret)
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ASSERTOK_H
diff --git a/audio/common/all-versions/test/utility/include/utility/Documentation.h b/audio/common/all-versions/test/utility/include/utility/Documentation.h
new file mode 100644
index 0000000..e10cf79
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/Documentation.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+namespace doc {
+namespace detail {
+const char* getTestName() {
+    return ::testing::UnitTest::GetInstance()->current_test_info()->name();
+}
+}  // namespace detail
+
+/** Document the current test case.
+ * Eg: calling `doc::test("Dump the state of the hal")` in the "debugDump" test
+ * will output:
+ *   <testcase name="debugDump" status="run" time="6"
+ *             classname="AudioPrimaryHidlTest"
+               description="Dump the state of the hal." />
+ * see
+ https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#logging-additional-information
+ */
+void test(const std::string& testCaseDocumentation) {
+    ::testing::Test::RecordProperty("description", testCaseDocumentation);
+}
+
+/** Document why a test was not fully run. Usually due to an optional feature
+ * not implemented. */
+void partialTest(const std::string& reason) {
+    LOG(INFO) << "Test " << detail::getTestName() << " partially run: " << reason;
+    ::testing::Test::RecordProperty("partialyRunTest", reason);
+}
+
+/** Add a note to the test. */
+void note(const std::string& note) {
+    LOG(INFO) << "Test " << detail::getTestName() << " noted: " << note;
+    ::testing::Test::RecordProperty("note", note);
+}
+}  // namespace doc
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN
diff --git a/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
new file mode 100644
index 0000000..a96d06e
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/EnvironmentTearDown.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H
+
+#include <functional>
+#include <list>
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+/** Register callback for static object destruction
+ * Avoid destroying static objects after main return.
+ * Post main return destruction leads to incorrect gtest timing measurements as
+ * well as harder debuging if anything goes wrong during destruction. */
+class Environment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    using TearDownFunc = std::function<void()>;
+    void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_back(std::move(tearDown)); }
+
+   private:
+    void HidlTearDown() override {
+        // Call the tear downs in reverse order of insertion
+        for (auto& tearDown : tearDowns) {
+            tearDown();
+        }
+    }
+    std::list<TearDownFunc> tearDowns;
+};
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H
diff --git a/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h b/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h
new file mode 100644
index 0000000..88a67e0
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/PrettyPrintAudioTypes.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_HAL_VERSION
+#error "AUDIO_HAL_VERSION must be set before including this file."
+#endif
+
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
+
+#include <iosfwd>
+#include <utility>
+
+/** @file Use HIDL generated toString methods to pretty print gtest errors
+ *        Unfortunately Gtest does not offer a template to specialize, only
+ *        overloading PrintTo.
+ *  @note that this overload can NOT be template because
+ *        the fallback is already template, resulting in ambiguity.
+ *  @note that the overload MUST be in the exact namespace
+ *        the type is declared in, as per the ADL rules.
+ */
+
+namespace android {
+namespace hardware {
+namespace audio {
+
+#define DEFINE_GTEST_PRINT_TO(T) \
+    inline void PrintTo(const T& val, ::std::ostream* os) { *os << toString(val); }
+
+namespace AUDIO_HAL_VERSION {
+DEFINE_GTEST_PRINT_TO(Result)
+}  // namespace AUDIO_HAL_VERSION
+
+namespace common {
+namespace AUDIO_HAL_VERSION {
+DEFINE_GTEST_PRINT_TO(AudioConfig)
+DEFINE_GTEST_PRINT_TO(AudioDevice)
+DEFINE_GTEST_PRINT_TO(AudioChannelMask)
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace common
+
+#undef DEFINE_GTEST_PRINT_TO
+
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
diff --git a/audio/common/all-versions/test/utility/include/utility/ReturnIn.h b/audio/common/all-versions/test/utility/include/utility/ReturnIn.h
new file mode 100644
index 0000000..2b92a21
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/ReturnIn.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_RETURN_IN_H
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_RETURN_IN_H
+
+#include <tuple>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+namespace detail {
+// Helper class to generate the HIDL synchronous callback
+template <class... ResultStore>
+class ReturnIn {
+   public:
+    // Provide to the constructor the variables where the output parameters must be copied
+    // TODO: take pointers to match google output parameter style ?
+    ReturnIn(ResultStore&... ts) : results(ts...) {}
+    // Synchronous callback
+    template <class... Results>
+    void operator()(Results&&... results) {
+        set(std::forward<Results>(results)...);
+    }
+
+   private:
+    // Recursively set all output parameters
+    template <class Head, class... Tail>
+    void set(Head&& head, Tail&&... tail) {
+        std::get<sizeof...(ResultStore) - sizeof...(Tail) - 1>(results) = std::forward<Head>(head);
+        set(tail...);
+    }
+    // Trivial case
+    void set() {}
+
+    // All variables to set are stored here
+    std::tuple<ResultStore&...> results;
+};
+}  // namespace detail
+
+// Generate the HIDL synchronous callback with a copy policy
+// Input: the variables (lvalue reference) where to save the return values
+// Output: the callback to provide to a HIDL call with a synchronous callback
+// The output parameters *will be copied* do not use this function if you have
+// a zero copy policy
+template <class... ResultStore>
+detail::ReturnIn<ResultStore...> returnIn(ResultStore&... ts) {
+    return {ts...};
+}
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_RETURN_IN_H
diff --git a/audio/common/all-versions/test/utility/include/utility/ValidateXml.h b/audio/common/all-versions/test/utility/include/utility/ValidateXml.h
new file mode 100644
index 0000000..95080d1
--- /dev/null
+++ b/audio/common/all-versions/test/utility/include/utility/ValidateXml.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_VALIDATE_XML_H
+#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_VALIDATE_XML_H
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+/** Validate the provided XmlFile with the provided xsdFile.
+ * Intended to use with ASSERT_PRED_FORMAT2 as such:
+ *   ASSERT_PRED_FORMAT2(validateXml, pathToXml, pathToXsd);
+ * See ASSERT_VALID_XML for a helper macro.
+ */
+::testing::AssertionResult validateXml(const char* xmlFilePathExpr, const char* xsdFilePathExpr,
+                                       const char* xmlFilePath, const char* xsdFilePath);
+
+/** Helper gtest ASSERT to test XML validity against an XSD. */
+#define ASSERT_VALID_XML(xmlFilePath, xsdFilePath)                                      \
+    ASSERT_PRED_FORMAT2(::android::hardware::audio::common::test::utility::validateXml, \
+                        xmlFilePath, xsdFilePath)
+
+/** Helper gtest EXPECT to test XML validity against an XSD. */
+#define EXPECT_VALID_XML(xmlFilePath, xsdFilePath)                                      \
+    EXPECT_PRED_FORMAT2(::android::hardware::audio::common::test::utility::validateXml, \
+                        xmlFilePath, xsdFilePath)
+
+/** Validate an XML according to an xsd.
+ * The XML file must be in at least one of the provided locations.
+ * If multiple are found, all are validated.
+ */
+::testing::AssertionResult validateXmlMultipleLocations(
+    const char* xmlFileNameExpr, const char* xmlFileLocationsExpr, const char* xsdFilePathExpr,
+    const char* xmlFileName, std::vector<const char*> xmlFileLocations, const char* xsdFilePath);
+
+/** ASSERT that an XML is valid according to an xsd.
+ * The XML file must be in at least one of the provided locations.
+ * If multiple are found, all are validated.
+ */
+#define ASSERT_ONE_VALID_XML_MULTIPLE_LOCATIONS(xmlFileName, xmlFileLocations, xsdFilePath) \
+    ASSERT_PRED_FORMAT3(                                                                    \
+        ::android::hardware::audio::common::test::utility::validateXmlMultipleLocations,    \
+        xmlFileName, xmlFileLocations, xsdFilePath)
+
+/** EXPECT an XML to be valid according to an xsd.
+ * The XML file must be in at least one of the provided locations.
+ * If multiple are found, all are validated.
+ */
+#define EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(xmlFileName, xmlFileLocations, xsdFilePath) \
+    EXPECT_PRED_FORMAT3(                                                                    \
+        ::android::hardware::audio::common::test::utility::validateXmlMultipleLocations,    \
+        xmlFileName, xmlFileLocations, xsdFilePath)
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_VALIDATE_XML_H
diff --git a/audio/common/all-versions/test/utility/src/ValidateXml.cpp b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
new file mode 100644
index 0000000..5030af5
--- /dev/null
+++ b/audio/common/all-versions/test/utility/src/ValidateXml.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ValidateAudioConfig"
+#include <utils/Log.h>
+
+#include <numeric>
+
+#define LIBXML_SCHEMAS_ENABLED
+#include <libxml/xmlschemastypes.h>
+#define LIBXML_XINCLUDE_ENABLED
+#include <libxml/xinclude.h>
+
+#include <memory>
+#include <string>
+
+#include "ValidateXml.h"
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace common {
+namespace test {
+namespace utility {
+
+/** Map libxml2 structures to their corresponding deleters. */
+template <class T>
+constexpr void (*xmlDeleter)(T* t);
+template <>
+constexpr auto xmlDeleter<xmlSchema> = xmlSchemaFree;
+template <>
+constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
+template <>
+constexpr auto xmlDeleter<xmlSchemaParserCtxt> = xmlSchemaFreeParserCtxt;
+template <>
+constexpr auto xmlDeleter<xmlSchemaValidCtxt> = xmlSchemaFreeValidCtxt;
+
+/** @return a unique_ptr with the correct deleter for the libxml2 object. */
+template <class T>
+constexpr auto make_xmlUnique(T* t) {
+    // Wrap deleter in lambda to enable empty base optimization
+    auto deleter = [](T* t) { xmlDeleter<T>(t); };
+    return std::unique_ptr<T, decltype(deleter)>{t, deleter};
+}
+
+/** Class that handles libxml2 initialization and cleanup. NOT THREAD SAFE*/
+struct Libxml2Global {
+    Libxml2Global() {
+        xmlLineNumbersDefault(1);  // Better error message
+        xmlSetGenericErrorFunc(this, errorCb);
+    }
+    ~Libxml2Global() {
+        // TODO: check if all those cleanup are needed
+        xmlSetGenericErrorFunc(nullptr, nullptr);
+        xmlSchemaCleanupTypes();
+        xmlCleanupParser();
+        xmlCleanupThreads();
+    }
+
+    const std::string& getErrors() { return errors; }
+
+   private:
+    static void errorCb(void* ctxt, const char* msg, ...) {
+        auto* self = static_cast<Libxml2Global*>(ctxt);
+        va_list args;
+        va_start(args, msg);
+
+        char* formatedMsg;
+        if (vasprintf(&formatedMsg, msg, args) >= 0) {
+            LOG_PRI(ANDROID_LOG_ERROR, LOG_TAG, "%s", formatedMsg);
+            self->errors += "Error: ";
+            self->errors += formatedMsg;
+        }
+        free(formatedMsg);
+
+        va_end(args);
+    }
+    std::string errors;
+};
+
+::testing::AssertionResult validateXml(const char* xmlFilePathExpr, const char* xsdFilePathExpr,
+                                       const char* xmlFilePath, const char* xsdFilePath) {
+    Libxml2Global libxml2;
+
+    auto context = [&]() {
+        return std::string() + "  While validating: " + xmlFilePathExpr +
+               "\n          Which is: " + xmlFilePath + "\nAgainst the schema: " + xsdFilePathExpr +
+               "\n          Which is: " + xsdFilePath + "\nLibxml2 errors:\n" + libxml2.getErrors();
+    };
+
+    auto schemaParserCtxt = make_xmlUnique(xmlSchemaNewParserCtxt(xsdFilePath));
+    auto schema = make_xmlUnique(xmlSchemaParse(schemaParserCtxt.get()));
+    if (schema == nullptr) {
+        return ::testing::AssertionFailure() << "Failed to parse schema (xsd)\n" << context();
+    }
+
+    auto doc = make_xmlUnique(xmlReadFile(xmlFilePath, nullptr, 0));
+    if (doc == nullptr) {
+        return ::testing::AssertionFailure() << "Failed to parse xml\n" << context();
+    }
+
+    if (xmlXIncludeProcess(doc.get()) == -1) {
+        return ::testing::AssertionFailure() << "Failed to resolve xincludes in xml\n" << context();
+    }
+
+    auto schemaCtxt = make_xmlUnique(xmlSchemaNewValidCtxt(schema.get()));
+    int ret = xmlSchemaValidateDoc(schemaCtxt.get(), doc.get());
+    if (ret > 0) {
+        return ::testing::AssertionFailure() << "XML is not valid according to the xsd\n"
+                                             << context();
+    }
+    if (ret < 0) {
+        return ::testing::AssertionFailure() << "Internal or API error\n" << context();
+    }
+
+    return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult validateXmlMultipleLocations(
+    const char* xmlFileNameExpr, const char* xmlFileLocationsExpr, const char* xsdFilePathExpr,
+    const char* xmlFileName, std::vector<const char*> xmlFileLocations, const char* xsdFilePath) {
+    using namespace std::string_literals;
+
+    std::vector<std::string> errors;
+    std::vector<std::string> foundFiles;
+
+    for (const char* location : xmlFileLocations) {
+        std::string xmlFilePath = location + "/"s + xmlFileName;
+        if (access(xmlFilePath.c_str(), F_OK) != 0) {
+            // If the file does not exist ignore this location and fallback on the next one
+            continue;
+        }
+        foundFiles.push_back("    " + xmlFilePath + '\n');
+        auto result = validateXml("xmlFilePath", xsdFilePathExpr, xmlFilePath.c_str(), xsdFilePath);
+        if (!result) {
+            errors.push_back(result.message());
+        }
+    }
+
+    if (foundFiles.empty()) {
+        errors.push_back("No xml file found in provided locations.\n");
+    }
+
+    return ::testing::AssertionResult(errors.empty())
+           << errors.size() << " error" << (errors.size() == 1 ? " " : "s ")
+           << std::accumulate(begin(errors), end(errors), "occurred during xml validation:\n"s)
+           << "     While validating all: " << xmlFileNameExpr
+           << "\n                 Which is: " << xmlFileName
+           << "\n In the following folders: " << xmlFileLocationsExpr
+           << "\n                 Which is: " << ::testing::PrintToString(xmlFileLocations);
+}
+
+}  // namespace utility
+}  // namespace test
+}  // namespace common
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/common/all-versions/util/Android.bp b/audio/common/all-versions/util/Android.bp
new file mode 100644
index 0000000..5d33a3a
--- /dev/null
+++ b/audio/common/all-versions/util/Android.bp
@@ -0,0 +1,10 @@
+cc_library_headers {
+    name: "android.hardware.audio.common.util@all-versions",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+
+    export_include_dirs: ["include"],
+}
diff --git a/audio/common/all-versions/util/include/common/all-versions/IncludeGuard.h b/audio/common/all-versions/util/include/common/all-versions/IncludeGuard.h
new file mode 100644
index 0000000..2d54816
--- /dev/null
+++ b/audio/common/all-versions/util/include/common/all-versions/IncludeGuard.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AUDIO_HAL_VERSION
+#error "AUDIO_HAL_VERSION must be set before including this file."
+#endif
diff --git a/audio/common/test/OWNERS b/audio/common/test/OWNERS
deleted file mode 100644
index 8711a9f..0000000
--- a/audio/common/test/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-elaurent@google.com
-krocard@google.com
-mnaganov@google.com
-yim@google.com
-zhuoyao@google.com
\ No newline at end of file
diff --git a/audio/common/test/utility/OWNERS b/audio/common/test/utility/OWNERS
deleted file mode 100644
index 6fdc97c..0000000
--- a/audio/common/test/utility/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-elaurent@google.com
-krocard@google.com
-mnaganov@google.com
diff --git a/audio/common/test/utility/include/utility/AssertOk.h b/audio/common/test/utility/include/utility/AssertOk.h
deleted file mode 100644
index d8aa451..0000000
--- a/audio/common/test/utility/include/utility/AssertOk.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ASSERTOK_H
-#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ASSERTOK_H
-
-#include <algorithm>
-#include <vector>
-
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace common {
-namespace test {
-namespace utility {
-
-namespace detail {
-
-// This is a detail namespace, thus it is OK to import a class as nobody else is
-// allowed to use it
-using ::android::hardware::Return;
-using ::android::hardware::audio::V2_0::Result;
-
-template <class T>
-inline ::testing::AssertionResult assertIsOk(const char* expr, const Return<T>& ret) {
-    return ::testing::AssertionResult(ret.isOk())
-           << "Expected: " << expr << "\n to be an OK Return but it is not: " << ret.description();
-}
-
-// Call continuation if the provided result isOk
-template <class T, class Continuation>
-inline ::testing::AssertionResult continueIfIsOk(const char* expr, const Return<T>& ret,
-                                                 Continuation continuation) {
-    auto isOkStatus = assertIsOk(expr, ret);
-    return !isOkStatus ? isOkStatus : continuation();
-}
-
-// Expect two equal Results
-inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
-                                               Result expected, Result result) {
-    return ::testing::AssertionResult(expected == result)
-           << "Value of: " << r_expr << "\n  Actual: " << ::testing::PrintToString(result)
-           << "\nExpected: " << e_expr << "\nWhich is: " << ::testing::PrintToString(expected);
-}
-
-// Expect two equal Results one being wrapped in an OK Return
-inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
-                                               Result expected, const Return<Result>& ret) {
-    return continueIfIsOk(r_expr, ret,
-                          [&] { return assertResult(e_expr, r_expr, expected, Result{ret}); });
-}
-
-// Expect a Result to be part of a list of Results
-inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
-                                               const std::vector<Result>& expected, Result result) {
-    if (std::find(expected.begin(), expected.end(), result) != expected.end()) {
-        return ::testing::AssertionSuccess();  // result is in expected
-    }
-    return ::testing::AssertionFailure()
-           << "Value of: " << r_expr << "\n  Actual: " << ::testing::PrintToString(result)
-           << "\nExpected one of: " << e_expr
-           << "\n       Which is: " << ::testing::PrintToString(expected);
-}
-
-// Expect a Result wrapped in an OK Return to be part of a list of Results
-inline ::testing::AssertionResult assertResult(const char* e_expr, const char* r_expr,
-                                               const std::vector<Result>& expected,
-                                               const Return<Result>& ret) {
-    return continueIfIsOk(r_expr, ret,
-                          [&] { return assertResult(e_expr, r_expr, expected, Result{ret}); });
-}
-
-inline ::testing::AssertionResult assertOk(const char* expr, const Return<void>& ret) {
-    return assertIsOk(expr, ret);
-}
-
-inline ::testing::AssertionResult assertOk(const char* expr, Result result) {
-    return ::testing::AssertionResult(result == Result::OK)
-           << "Expected success: " << expr << "\nActual: " << ::testing::PrintToString(result);
-}
-
-inline ::testing::AssertionResult assertOk(const char* expr, const Return<Result>& ret) {
-    return continueIfIsOk(expr, ret, [&] { return assertOk(expr, Result{ret}); });
-}
-}
-
-#define ASSERT_IS_OK(ret) ASSERT_PRED_FORMAT1(detail::assertIsOk, ret)
-#define EXPECT_IS_OK(ret) EXPECT_PRED_FORMAT1(detail::assertIsOk, ret)
-
-// Test anything provided is and contains only OK
-#define ASSERT_OK(ret) ASSERT_PRED_FORMAT1(detail::assertOk, ret)
-#define EXPECT_OK(ret) EXPECT_PRED_FORMAT1(detail::assertOk, ret)
-
-#define ASSERT_RESULT(expected, ret) ASSERT_PRED_FORMAT2(detail::assertResult, expected, ret)
-#define EXPECT_RESULT(expected, ret) EXPECT_PRED_FORMAT2(detail::assertResult, expected, ret)
-
-}  // utility
-}  // test
-}  // common
-}  // audio
-}  // test
-}  // utility
-
-#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ASSERTOK_H
diff --git a/audio/common/test/utility/include/utility/Documentation.h b/audio/common/test/utility/include/utility/Documentation.h
deleted file mode 100644
index a45cad6..0000000
--- a/audio/common/test/utility/include/utility/Documentation.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN
-#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN
-
-#include <android-base/logging.h>
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace common {
-namespace test {
-namespace utility {
-
-namespace doc {
-namespace detail {
-const char* getTestName() {
-    return ::testing::UnitTest::GetInstance()->current_test_info()->name();
-}
-}  // namespace detail
-
-/** Document the current test case.
- * Eg: calling `doc::test("Dump the state of the hal")` in the "debugDump" test
- * will output:
- *   <testcase name="debugDump" status="run" time="6"
- *             classname="AudioPrimaryHidlTest"
-               description="Dump the state of the hal." />
- * see
- https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#logging-additional-information
- */
-void test(const std::string& testCaseDocumentation) {
-    ::testing::Test::RecordProperty("description", testCaseDocumentation);
-}
-
-/** Document why a test was not fully run. Usually due to an optional feature
- * not implemented. */
-void partialTest(const std::string& reason) {
-    LOG(INFO) << "Test " << detail::getTestName() << " partially run: " << reason;
-    ::testing::Test::RecordProperty("partialyRunTest", reason);
-}
-
-/** Add a note to the test. */
-void note(const std::string& note) {
-    LOG(INFO) << "Test " << detail::getTestName() << " noted: " << note;
-    ::testing::Test::RecordProperty("note", note);
-}
-}  // namespace doc
-
-}  // utility
-}  // test
-}  // common
-}  // audio
-}  // test
-}  // utility
-
-#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN
diff --git a/audio/common/test/utility/include/utility/EnvironmentTearDown.h b/audio/common/test/utility/include/utility/EnvironmentTearDown.h
deleted file mode 100644
index 15b0bd8..0000000
--- a/audio/common/test/utility/include/utility/EnvironmentTearDown.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H
-#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H
-
-#include <functional>
-#include <list>
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace common {
-namespace test {
-namespace utility {
-
-/** Register callback for static object destruction
- * Avoid destroying static objects after main return.
- * Post main return destruction leads to incorrect gtest timing measurements as
- * well as harder debuging if anything goes wrong during destruction. */
-class Environment : public ::testing::Environment {
-   public:
-    using TearDownFunc = std::function<void()>;
-    void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_back(std::move(tearDown)); }
-
-   private:
-    void TearDown() override {
-        // Call the tear downs in reverse order of insertion
-        for (auto& tearDown : tearDowns) {
-            tearDown();
-        }
-    }
-    std::list<TearDownFunc> tearDowns;
-};
-
-}  // utility
-}  // test
-}  // common
-}  // audio
-}  // test
-}  // utility
-
-#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_ENVIRONMENT_TEARDOWN_H
diff --git a/audio/common/test/utility/include/utility/PrettyPrintAudioTypes.h b/audio/common/test/utility/include/utility/PrettyPrintAudioTypes.h
deleted file mode 100644
index 37059e7..0000000
--- a/audio/common/test/utility/include/utility/PrettyPrintAudioTypes.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
-#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
-
-#include <iosfwd>
-#include <type_traits>
-
-#include <android/hardware/audio/2.0/types.h>
-#include <android/hardware/audio/common/2.0/types.h>
-
-/** @file Use HIDL generated toString methods to pretty print gtest errors */
-
-namespace prettyPrintAudioTypesDetail {
-
-// Print the value of an enum as hex
-template <class Enum>
-inline void printUnderlyingValue(Enum value, ::std::ostream* os) {
-    *os << std::hex << " (0x" << static_cast<std::underlying_type_t<Enum>>(value) << ")";
-}
-
-}  // namespace detail
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace V2_0 {
-
-inline void PrintTo(const Result& result, ::std::ostream* os) {
-    *os << toString(result);
-    prettyPrintAudioTypesDetail::printUnderlyingValue(result, os);
-}
-
-}  // namespace V2_0
-namespace common {
-namespace V2_0 {
-
-inline void PrintTo(const AudioConfig& config, ::std::ostream* os) {
-    *os << toString(config);
-}
-
-inline void PrintTo(const AudioDevice& device, ::std::ostream* os) {
-    *os << toString(device);
-    prettyPrintAudioTypesDetail::printUnderlyingValue(device, os);
-}
-
-inline void PrintTo(const AudioChannelMask& channelMask, ::std::ostream* os) {
-    *os << toString(channelMask);
-    prettyPrintAudioTypesDetail::printUnderlyingValue(channelMask, os);
-}
-
-}  // namespace V2_0
-}  // namespace common
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_PRETTY_PRINT_AUDIO_TYPES_H
diff --git a/audio/common/test/utility/include/utility/ReturnIn.h b/audio/common/test/utility/include/utility/ReturnIn.h
deleted file mode 100644
index 08d502f..0000000
--- a/audio/common/test/utility/include/utility/ReturnIn.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_RETURN_IN_H
-#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_RETURN_IN_H
-
-#include <tuple>
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace common {
-namespace test {
-namespace utility {
-
-namespace detail {
-// Helper class to generate the HIDL synchronous callback
-template <class... ResultStore>
-class ReturnIn {
-   public:
-    // Provide to the constructor the variables where the output parameters must be copied
-    // TODO: take pointers to match google output parameter style ?
-    ReturnIn(ResultStore&... ts) : results(ts...) {}
-    // Synchronous callback
-    template <class... Results>
-    void operator()(Results&&... results) {
-        set(std::forward<Results>(results)...);
-    }
-
-   private:
-    // Recursively set all output parameters
-    template <class Head, class... Tail>
-    void set(Head&& head, Tail&&... tail) {
-        std::get<sizeof...(ResultStore) - sizeof...(Tail) - 1>(results) = std::forward<Head>(head);
-        set(tail...);
-    }
-    // Trivial case
-    void set() {}
-
-    // All variables to set are stored here
-    std::tuple<ResultStore&...> results;
-};
-}  // namespace detail
-
-// Generate the HIDL synchronous callback with a copy policy
-// Input: the variables (lvalue reference) where to save the return values
-// Output: the callback to provide to a HIDL call with a synchronous callback
-// The output parameters *will be copied* do not use this function if you have
-// a zero copy policy
-template <class... ResultStore>
-detail::ReturnIn<ResultStore...> returnIn(ResultStore&... ts) {
-    return {ts...};
-}
-
-}  // utility
-}  // test
-}  // common
-}  // audio
-}  // test
-}  // utility
-
-#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_RETURN_IN_H
diff --git a/audio/common/test/utility/include/utility/ValidateXml.h b/audio/common/test/utility/include/utility/ValidateXml.h
deleted file mode 100644
index fdfa506..0000000
--- a/audio/common/test/utility/include/utility/ValidateXml.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_VALIDATE_XML_H
-#define ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_VALIDATE_XML_H
-
-#include <gtest/gtest.h>
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace common {
-namespace test {
-namespace utility {
-
-/** Validate the provided XmlFile with the provided xsdFile.
- * Intended to use with ASSERT_PRED_FORMAT2 as such:
- *   ASSERT_PRED_FORMAT2(validateXml, pathToXml, pathToXsd);
- * See ASSERT_VALID_XML for a helper macro.
- */
-::testing::AssertionResult validateXml(const char* xmlFilePathExpr, const char* xsdFilePathExpr,
-                                       const char* xmlFilePath, const char* xsdPathName);
-
-/** Helper gtest ASSERT to test xml validity against an xsd. */
-#define ASSERT_VALID_XML(xmlFilePath, xsdFilePath)                                      \
-    ASSERT_PRED_FORMAT2(::android::hardware::audio::common::test::utility::validateXml, \
-                        xmlFilePath, xsdFilePath)
-
-}  // utility
-}  // test
-}  // common
-}  // audio
-}  // test
-}  // utility
-
-#endif  // ANDROID_HARDWARE_AUDIO_COMMON_TEST_UTILITY_VALIDATE_XML_H
diff --git a/audio/common/test/utility/src/ValidateXml.cpp b/audio/common/test/utility/src/ValidateXml.cpp
deleted file mode 100644
index 784f940..0000000
--- a/audio/common/test/utility/src/ValidateXml.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ValidateAudioConfig"
-#include <utils/Log.h>
-
-#define LIBXML_SCHEMAS_ENABLED
-#include <libxml/xmlschemastypes.h>
-#define LIBXML_XINCLUDE_ENABLED
-#include <libxml/xinclude.h>
-
-#include <memory>
-#include <string>
-
-#include "ValidateXml.h"
-
-namespace android {
-namespace hardware {
-namespace audio {
-namespace common {
-namespace test {
-namespace utility {
-
-/** Map libxml2 structures to their corresponding deleters. */
-template <class T>
-constexpr void (*xmlDeleter)(T* t);
-template <>
-constexpr auto xmlDeleter<xmlSchema> = xmlSchemaFree;
-template <>
-constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
-template <>
-constexpr auto xmlDeleter<xmlSchemaParserCtxt> = xmlSchemaFreeParserCtxt;
-template <>
-constexpr auto xmlDeleter<xmlSchemaValidCtxt> = xmlSchemaFreeValidCtxt;
-
-/** @return a unique_ptr with the correct deleter for the libxml2 object. */
-template <class T>
-constexpr auto make_xmlUnique(T* t) {
-    // Wrap deleter in lambda to enable empty base optimization
-    auto deleter = [](T* t) { xmlDeleter<T>(t); };
-    return std::unique_ptr<T, decltype(deleter)>{t, deleter};
-}
-
-/** Class that handles libxml2 initialization and cleanup. NOT THREAD SAFE*/
-struct Libxml2Global {
-    Libxml2Global() {
-        xmlLineNumbersDefault(1);  // Better error message
-        xmlSetGenericErrorFunc(this, errorCb);
-    }
-    ~Libxml2Global() {
-        // TODO: check if all those cleanup are needed
-        xmlSetGenericErrorFunc(nullptr, nullptr);
-        xmlSchemaCleanupTypes();
-        xmlCleanupParser();
-        xmlCleanupThreads();
-    }
-
-    const std::string& getErrors() { return errors; }
-
-   private:
-    static void errorCb(void* ctxt, const char* msg, ...) {
-        auto* self = static_cast<Libxml2Global*>(ctxt);
-        va_list args;
-        va_start(args, msg);
-
-        char* formatedMsg;
-        if (vasprintf(&formatedMsg, msg, args) >= 0) {
-            LOG_PRI(ANDROID_LOG_ERROR, LOG_TAG, "%s", formatedMsg);
-            self->errors += "Error: ";
-            self->errors += formatedMsg;
-        }
-        free(formatedMsg);
-
-        va_end(args);
-    }
-    std::string errors;
-};
-
-::testing::AssertionResult validateXml(const char* xmlFilePathExpr, const char* xsdFilePathExpr,
-                                       const char* xmlFilePath, const char* xsdFilePath) {
-    Libxml2Global libxml2;
-
-    auto context = [&]() {
-        return std::string() + "    While validating: " + xmlFilePathExpr +
-               "\n          Which is: " + xmlFilePath + "\nAgainst the schema: " + xsdFilePathExpr +
-               "\n          Which is: " + xsdFilePath + "Libxml2 errors\n" + libxml2.getErrors();
-    };
-
-    auto schemaParserCtxt = make_xmlUnique(xmlSchemaNewParserCtxt(xsdFilePath));
-    auto schema = make_xmlUnique(xmlSchemaParse(schemaParserCtxt.get()));
-    if (schema == nullptr) {
-        return ::testing::AssertionFailure() << "Failed to parse schema (xsd)\n" << context();
-    }
-
-    auto doc = make_xmlUnique(xmlReadFile(xmlFilePath, nullptr, 0));
-    if (doc == nullptr) {
-        return ::testing::AssertionFailure() << "Failed to parse xml\n" << context();
-    }
-
-    if (xmlXIncludeProcess(doc.get()) == -1) {
-        return ::testing::AssertionFailure() << "Failed to resolve xincludes in xml\n" << context();
-    }
-
-    auto schemaCtxt = make_xmlUnique(xmlSchemaNewValidCtxt(schema.get()));
-    int ret = xmlSchemaValidateDoc(schemaCtxt.get(), doc.get());
-    if (ret > 0) {
-        return ::testing::AssertionFailure() << "xml is not valid according to the xsd.\n"
-                                             << context();
-    }
-    if (ret < 0) {
-        return ::testing::AssertionFailure() << "Internal or API error\n" << context();
-    }
-
-    return ::testing::AssertionSuccess();
-}
-
-}  // utility
-}  // test
-}  // common
-}  // audio
-}  // test
-}  // utility
diff --git a/audio/core/2.0/default/Android.bp b/audio/core/2.0/default/Android.bp
new file mode 100644
index 0000000..9847886
--- /dev/null
+++ b/audio/core/2.0/default/Android.bp
@@ -0,0 +1,49 @@
+cc_library_shared {
+    name: "android.hardware.audio@2.0-impl",
+    relative_install_path: "hw",
+    proprietary: true,
+    vendor: true,
+    srcs: [
+        "Conversions.cpp",
+        "Device.cpp",
+        "DevicesFactory.cpp",
+        "ParametersUtil.cpp",
+        "PrimaryDevice.cpp",
+        "Stream.cpp",
+        "StreamIn.cpp",
+        "StreamOut.cpp",
+    ],
+
+    defaults: ["hidl_defaults"],
+
+    export_include_dirs: ["include"],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "android.hardware.audio@2.0",
+        "android.hardware.audio.common@2.0",
+        "android.hardware.audio.common@2.0-util",
+        "android.hardware.audio.common-util",
+    ],
+
+    header_libs: [
+        "android.hardware.audio.common.util@all-versions",
+        "android.hardware.audio.core@all-versions-impl",
+        "libaudioclient_headers",
+        "libaudio_system_headers",
+        "libhardware_headers",
+        "libmedia_headers",
+    ],
+
+    whole_static_libs: [
+        "libmedia_helper",
+    ],
+
+}
diff --git a/audio/core/2.0/default/Conversions.cpp b/audio/core/2.0/default/Conversions.cpp
new file mode 100644
index 0000000..6c32090
--- /dev/null
+++ b/audio/core/2.0/default/Conversions.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "core/2.0/default/Conversions.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/Conversions.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/core/2.0/default/Device.cpp b/audio/core/2.0/default/Device.cpp
new file mode 100644
index 0000000..221ea5c
--- /dev/null
+++ b/audio/core/2.0/default/Device.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DeviceHAL"
+
+#include "core/2.0/default/Device.h"
+#include <HidlUtils.h>
+#include "core/2.0/default/Conversions.h"
+#include "core/2.0/default/StreamIn.h"
+#include "core/2.0/default/StreamOut.h"
+#include "core/all-versions/default/Util.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/Device.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/core/2.0/default/DevicesFactory.cpp b/audio/core/2.0/default/DevicesFactory.cpp
new file mode 100644
index 0000000..65a9ccd
--- /dev/null
+++ b/audio/core/2.0/default/DevicesFactory.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DevicesFactoryHAL"
+
+#include "core/2.0/default/DevicesFactory.h"
+#include "core/2.0/default/Device.h"
+#include "core/2.0/default/PrimaryDevice.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/DevicesFactory.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/common/2.0/default/OWNERS b/audio/core/2.0/default/OWNERS
similarity index 100%
rename from audio/common/2.0/default/OWNERS
rename to audio/core/2.0/default/OWNERS
diff --git a/audio/core/2.0/default/ParametersUtil.cpp b/audio/core/2.0/default/ParametersUtil.cpp
new file mode 100644
index 0000000..33a3ad9
--- /dev/null
+++ b/audio/core/2.0/default/ParametersUtil.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "core/2.0/default/ParametersUtil.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/ParametersUtil.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/core/2.0/default/PrimaryDevice.cpp b/audio/core/2.0/default/PrimaryDevice.cpp
new file mode 100644
index 0000000..ce57403
--- /dev/null
+++ b/audio/core/2.0/default/PrimaryDevice.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PrimaryDeviceHAL"
+
+#include "core/2.0/default/PrimaryDevice.h"
+#include "core/all-versions/default/Util.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/PrimaryDevice.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/core/2.0/default/Stream.cpp b/audio/core/2.0/default/Stream.cpp
new file mode 100644
index 0000000..69ee659
--- /dev/null
+++ b/audio/core/2.0/default/Stream.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "StreamHAL"
+
+#include "core/2.0/default/Stream.h"
+#include "common/all-versions/default/EffectMap.h"
+#include "core/2.0/default/Conversions.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/Stream.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/core/2.0/default/StreamIn.cpp b/audio/core/2.0/default/StreamIn.cpp
new file mode 100644
index 0000000..6b8776e
--- /dev/null
+++ b/audio/core/2.0/default/StreamIn.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "StreamInHAL"
+
+#include "core/2.0/default/StreamIn.h"
+#include "core/all-versions/default/Util.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/StreamIn.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/core/2.0/default/StreamOut.cpp b/audio/core/2.0/default/StreamOut.cpp
new file mode 100644
index 0000000..7f1461a
--- /dev/null
+++ b/audio/core/2.0/default/StreamOut.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "StreamOutHAL"
+
+#include "core/2.0/default/StreamOut.h"
+#include "core/all-versions/default/Util.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/StreamOut.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/core/2.0/default/include/core/2.0/default/Conversions.h b/audio/core/2.0/default/include/core/2.0/default/Conversions.h
new file mode 100644
index 0000000..b3a6ea8
--- /dev/null
+++ b/audio/core/2.0/default/include/core/2.0/default/Conversions.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_CONVERSIONS_H_
+#define ANDROID_HARDWARE_AUDIO_V2_0_CONVERSIONS_H_
+
+#include <android/hardware/audio/2.0/types.h>
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/Conversions.h>
+#undef AUDIO_HAL_VERSION
+
+#endif  // ANDROID_HARDWARE_AUDIO_V2_0_CONVERSIONS_H_
diff --git a/audio/core/2.0/default/include/core/2.0/default/Device.h b/audio/core/2.0/default/include/core/2.0/default/Device.h
new file mode 100644
index 0000000..3ec7464
--- /dev/null
+++ b/audio/core/2.0/default/include/core/2.0/default/Device.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H
+
+#include <android/hardware/audio/2.0/IDevice.h>
+
+#include "ParametersUtil.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/Device.h>
+#undef AUDIO_HAL_VERSION
+
+#endif  // ANDROID_HARDWARE_AUDIO_V2_0_DEVICE_H
diff --git a/audio/core/2.0/default/include/core/2.0/default/DevicesFactory.h b/audio/core/2.0/default/include/core/2.0/default/DevicesFactory.h
new file mode 100644
index 0000000..8e8ee88
--- /dev/null
+++ b/audio/core/2.0/default/include/core/2.0/default/DevicesFactory.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H
+
+#include <android/hardware/audio/2.0/IDevicesFactory.h>
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/DevicesFactory.h>
+#undef AUDIO_HAL_VERSION
+
+#endif  // ANDROID_HARDWARE_AUDIO_V2_0_DEVICESFACTORY_H
diff --git a/audio/core/2.0/default/include/core/2.0/default/ParametersUtil.h b/audio/core/2.0/default/include/core/2.0/default/ParametersUtil.h
new file mode 100644
index 0000000..a5c1c78
--- /dev/null
+++ b/audio/core/2.0/default/include/core/2.0/default/ParametersUtil.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_PARAMETERS_UTIL_H_
+#define ANDROID_HARDWARE_AUDIO_V2_0_PARAMETERS_UTIL_H_
+
+#include <android/hardware/audio/2.0/types.h>
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/ParametersUtil.h>
+#undef AUDIO_HAL_VERSION
+
+#endif  // ANDROID_HARDWARE_AUDIO_V2_0_PARAMETERS_UTIL_H_
diff --git a/audio/core/2.0/default/include/core/2.0/default/PrimaryDevice.h b/audio/core/2.0/default/include/core/2.0/default/PrimaryDevice.h
new file mode 100644
index 0000000..f898597
--- /dev/null
+++ b/audio/core/2.0/default/include/core/2.0/default/PrimaryDevice.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H
+
+#include <android/hardware/audio/2.0/IPrimaryDevice.h>
+
+#include "Device.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/PrimaryDevice.h>
+#undef AUDIO_HAL_VERSION
+
+#endif  // ANDROID_HARDWARE_AUDIO_V2_0_PRIMARYDEVICE_H
diff --git a/audio/core/2.0/default/include/core/2.0/default/Stream.h b/audio/core/2.0/default/include/core/2.0/default/Stream.h
new file mode 100644
index 0000000..a2d8456
--- /dev/null
+++ b/audio/core/2.0/default/include/core/2.0/default/Stream.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H
+
+#include <android/hardware/audio/2.0/IStream.h>
+
+#include "ParametersUtil.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/Stream.h>
+#undef AUDIO_HAL_VERSION
+
+#endif  // ANDROID_HARDWARE_AUDIO_V2_0_STREAM_H
diff --git a/audio/core/2.0/default/include/core/2.0/default/StreamIn.h b/audio/core/2.0/default/include/core/2.0/default/StreamIn.h
new file mode 100644
index 0000000..c36abbd
--- /dev/null
+++ b/audio/core/2.0/default/include/core/2.0/default/StreamIn.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
+
+#include <android/hardware/audio/2.0/IStreamIn.h>
+
+#include "Device.h"
+#include "Stream.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/StreamIn.h>
+#undef AUDIO_HAL_VERSION
+
+#endif  // ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
diff --git a/audio/core/2.0/default/include/core/2.0/default/StreamOut.h b/audio/core/2.0/default/include/core/2.0/default/StreamOut.h
new file mode 100644
index 0000000..ab35687
--- /dev/null
+++ b/audio/core/2.0/default/include/core/2.0/default/StreamOut.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
+#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
+
+#include <android/hardware/audio/2.0/IStreamOut.h>
+
+#include "Device.h"
+#include "Stream.h"
+
+#define AUDIO_HAL_VERSION V2_0
+#include <core/all-versions/default/StreamOut.h>
+#undef AUDIO_HAL_VERSION
+
+#endif  // ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
diff --git a/audio/2.0/vts/OWNERS b/audio/core/2.0/vts/OWNERS
similarity index 100%
rename from audio/2.0/vts/OWNERS
rename to audio/core/2.0/vts/OWNERS
diff --git a/audio/2.0/vts/functional/Android.bp b/audio/core/2.0/vts/functional/Android.bp
similarity index 100%
rename from audio/2.0/vts/functional/Android.bp
rename to audio/core/2.0/vts/functional/Android.bp
diff --git a/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
new file mode 100644
index 0000000..bb1d26f
--- /dev/null
+++ b/audio/core/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,1280 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalAudioV2_0TargetTest"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstdio>
+#include <initializer_list>
+#include <limits>
+#include <string>
+#include <vector>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <android-base/logging.h>
+
+#include <android/hardware/audio/2.0/IDevice.h>
+#include <android/hardware/audio/2.0/IDevicesFactory.h>
+#include <android/hardware/audio/2.0/IPrimaryDevice.h>
+#include <android/hardware/audio/2.0/types.h>
+#include <android/hardware/audio/common/2.0/types.h>
+
+#include "utility/AssertOk.h"
+#include "utility/Documentation.h"
+#include "utility/EnvironmentTearDown.h"
+#define AUDIO_HAL_VERSION V2_0
+#include "utility/PrettyPrintAudioTypes.h"
+#include "utility/ReturnIn.h"
+
+using std::initializer_list;
+using std::string;
+using std::to_string;
+using std::vector;
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::audio::V2_0::AudioDrain;
+using ::android::hardware::audio::V2_0::DeviceAddress;
+using ::android::hardware::audio::V2_0::IDevice;
+using ::android::hardware::audio::V2_0::IPrimaryDevice;
+using TtyMode = ::android::hardware::audio::V2_0::IPrimaryDevice::TtyMode;
+using ::android::hardware::audio::V2_0::IDevicesFactory;
+using ::android::hardware::audio::V2_0::IStream;
+using ::android::hardware::audio::V2_0::IStreamIn;
+using ::android::hardware::audio::V2_0::TimeSpec;
+using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters;
+using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus;
+using ::android::hardware::audio::V2_0::IStreamOut;
+using ::android::hardware::audio::V2_0::IStreamOutCallback;
+using ::android::hardware::audio::V2_0::MmapBufferInfo;
+using ::android::hardware::audio::V2_0::MmapPosition;
+using ::android::hardware::audio::V2_0::ParameterValue;
+using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::audio::common::V2_0::AudioChannelMask;
+using ::android::hardware::audio::common::V2_0::AudioConfig;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::common::V2_0::AudioHandleConsts;
+using ::android::hardware::audio::common::V2_0::AudioInputFlag;
+using ::android::hardware::audio::common::V2_0::AudioIoHandle;
+using ::android::hardware::audio::common::V2_0::AudioMode;
+using ::android::hardware::audio::common::V2_0::AudioOffloadInfo;
+using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
+using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::common::V2_0::ThreadInfo;
+
+using namespace ::android::hardware::audio::common::test::utility;
+
+class AudioHidlTestEnvironment : public ::Environment {
+   public:
+    virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+};
+
+// Instance to register global tearDown
+static AudioHidlTestEnvironment* environment;
+
+class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   protected:
+    // Convenient member to store results
+    Result res;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////// getService audio_devices_factory //////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Test all audio devices
+class AudioHidlTest : public HidlTest {
+   public:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp());  // setup base
+
+        if (devicesFactory == nullptr) {
+            environment->registerTearDown([] { devicesFactory.clear(); });
+            devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(
+                environment->getServiceName<IDevicesFactory>("default"));
+        }
+        ASSERT_TRUE(devicesFactory != nullptr);
+    }
+
+   protected:
+    // Cache the devicesFactory retrieval to speed up each test by ~0.5s
+    static sp<IDevicesFactory> devicesFactory;
+};
+sp<IDevicesFactory> AudioHidlTest::devicesFactory;
+
+TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
+    doc::test("test the getService (called in SetUp)");
+}
+
+TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
+    doc::test("test passing an invalid parameter to openDevice");
+    IDevicesFactory::Result result;
+    sp<IDevice> device;
+    ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device(-1), returnIn(result, device)));
+    ASSERT_EQ(IDevicesFactory::Result::INVALID_ARGUMENTS, result);
+    ASSERT_TRUE(device == nullptr);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// openDevice primary ///////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Test the primary device
+class AudioPrimaryHidlTest : public AudioHidlTest {
+   public:
+    /** Primary HAL test are NOT thread safe. */
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp());  // setup base
+
+        if (device == nullptr) {
+            IDevicesFactory::Result result;
+            sp<IDevice> baseDevice;
+            ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
+                                                 returnIn(result, baseDevice)));
+            ASSERT_OK(result);
+            ASSERT_TRUE(baseDevice != nullptr);
+
+            environment->registerTearDown([] { device.clear(); });
+            device = IPrimaryDevice::castFrom(baseDevice);
+            ASSERT_TRUE(device != nullptr);
+        }
+    }
+
+   protected:
+    // Cache the device opening to speed up each test by ~0.5s
+    static sp<IPrimaryDevice> device;
+};
+sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
+
+TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
+    doc::test("Test the openDevice (called in SetUp)");
+}
+
+TEST_F(AudioPrimaryHidlTest, Init) {
+    doc::test("Test that the audio primary hal initialized correctly");
+    ASSERT_OK(device->initCheck());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+template <class Property>
+class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
+   protected:
+    /** Test a property getter and setter. */
+    template <class Getter, class Setter>
+    void testAccessors(const string& propertyName, const vector<Property>& valuesToTest,
+                       Setter setter, Getter getter, const vector<Property>& invalidValues = {}) {
+        Property initialValue;  // Save initial value to restore it at the end
+                                // of the test
+        ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+        ASSERT_OK(res);
+
+        for (Property setValue : valuesToTest) {
+            SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
+                         testing::PrintToString(setValue));
+            ASSERT_OK((device.get()->*setter)(setValue));
+            Property getValue;
+            // Make sure the getter returns the same value just set
+            ASSERT_OK((device.get()->*getter)(returnIn(res, getValue)));
+            ASSERT_OK(res);
+            EXPECT_EQ(setValue, getValue);
+        }
+
+        for (Property invalidValue : invalidValues) {
+            SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
+                         testing::PrintToString(invalidValue));
+            EXPECT_RESULT(Result::INVALID_ARGUMENTS, (device.get()->*setter)(invalidValue));
+        }
+
+        ASSERT_OK((device.get()->*setter)(initialValue));  // restore initial value
+    }
+
+    /** Test the getter and setter of an optional feature. */
+    template <class Getter, class Setter>
+    void testOptionalAccessors(const string& propertyName, const vector<Property>& valuesToTest,
+                               Setter setter, Getter getter,
+                               const vector<Property>& invalidValues = {}) {
+        doc::test("Test the optional " + propertyName + " getters and setter");
+        {
+            SCOPED_TRACE("Test feature support by calling the getter");
+            Property initialValue;
+            ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+            if (res == Result::NOT_SUPPORTED) {
+                doc::partialTest(propertyName + " getter is not supported");
+                return;
+            }
+            ASSERT_OK(res);  // If it is supported it must succeed
+        }
+        // The feature is supported, test it
+        testAccessors(propertyName, valuesToTest, setter, getter, invalidValues);
+    }
+};
+
+using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>;
+
+TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
+    doc::test("Check that the mic can be muted and unmuted");
+    testAccessors("mic mute", {true, false, true}, &IDevice::setMicMute, &IDevice::getMicMute);
+    // TODO: check that the mic is really muted (all sample are 0)
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
+    doc::test(
+        "If master mute is supported, try to mute and unmute the master "
+        "output");
+    testOptionalAccessors("master mute", {true, false, true}, &IDevice::setMasterMute,
+                          &IDevice::getMasterMute);
+    // TODO: check that the master volume is really muted
+}
+
+using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
+TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
+    doc::test("Test the master volume if supported");
+    testOptionalAccessors(
+        "master volume", {0, 0.5, 1}, &IDevice::setMasterVolume, &IDevice::getMasterVolume,
+        {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()});
+    // TODO: check that the master volume is really changed
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// AudioPatches ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
+   protected:
+    bool areAudioPatchesSupported() {
+        auto result = device->supportsAudioPatches();
+        EXPECT_IS_OK(result);
+        return result;
+    }
+};
+
+TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
+    doc::test("Test if audio patches are supported");
+    if (!areAudioPatchesSupported()) {
+        doc::partialTest("Audio patches are not supported");
+        return;
+    }
+    // TODO: test audio patches
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////// Required and recommended audio format support ///////////////
+// From:
+// https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording
+// From:
+// https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback
+/////////// TODO: move to the beginning of the file for easier update ////////
+//////////////////////////////////////////////////////////////////////////////
+
+class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
+   public:
+    // Cache result ?
+    static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
+        return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
+                                  {8000, 11025, 16000, 22050, 32000, 44100},
+                                  {AudioFormat::PCM_16_BIT});
+    }
+
+    static const vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() {
+        return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
+                                  {24000, 48000}, {AudioFormat::PCM_16_BIT});
+    }
+
+    static const vector<AudioConfig> getSupportedPlaybackAudioConfig() {
+        // TODO: retrieve audio config supported by the platform
+        // as declared in the policy configuration
+        return {};
+    }
+
+    static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
+        return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100},
+                                  {AudioFormat::PCM_16_BIT});
+    }
+    static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
+        return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000},
+                                  {AudioFormat::PCM_16_BIT});
+    }
+    static const vector<AudioConfig> getSupportedCaptureAudioConfig() {
+        // TODO: retrieve audio config supported by the platform
+        // as declared in the policy configuration
+        return {};
+    }
+
+   private:
+    static const vector<AudioConfig> combineAudioConfig(vector<AudioChannelMask> channelMasks,
+                                                        vector<uint32_t> sampleRates,
+                                                        vector<AudioFormat> formats) {
+        vector<AudioConfig> configs;
+        for (auto channelMask : channelMasks) {
+            for (auto sampleRate : sampleRates) {
+                for (auto format : formats) {
+                    AudioConfig config{};
+                    // leave offloadInfo to 0
+                    config.channelMask = channelMask;
+                    config.sampleRateHz = sampleRate;
+                    config.format = format;
+                    // FIXME: leave frameCount to 0 ?
+                    configs.push_back(config);
+                }
+            }
+        }
+        return configs;
+    }
+};
+
+/** Generate a test name based on an audio config.
+ *
+ * As the only parameter changing are channel mask and sample rate,
+ * only print those ones in the test name.
+ */
+static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) {
+    const AudioConfig& config = info.param;
+    return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" +
+           // "MONO" is more clear than "FRONT_LEFT"
+           ((config.channelMask == AudioChannelMask::OUT_MONO ||
+             config.channelMask == AudioChannelMask::IN_MONO)
+                ? "MONO"
+                : toString(config.channelMask));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////// getInputBufferSize /////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// FIXME: execute input test only if platform declares
+// android.hardware.microphone
+//        how to get this value ? is it a property ???
+
+class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest,
+                                      public ::testing::WithParamInterface<AudioConfig> {
+   protected:
+    void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
+        uint64_t bufferSize;
+        ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
+
+        switch (res) {
+            case Result::INVALID_ARGUMENTS:
+                EXPECT_FALSE(supportRequired);
+                break;
+            case Result::OK:
+                // Check that the buffer is of a sane size
+                // For now only that it is > 0
+                EXPECT_GT(bufferSize, uint64_t(0));
+                break;
+            default:
+                FAIL() << "Invalid return status: " << ::testing::PrintToString(res);
+        }
+    }
+};
+
+// Test that the required capture config and those declared in the policy are
+// indeed supported
+class RequiredInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
+TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) {
+    doc::test(
+        "Input buffer size must be retrievable for a format with required "
+        "support.");
+    inputBufferSizeTest(GetParam(), true);
+}
+INSTANTIATE_TEST_CASE_P(
+    RequiredInputBufferSize, RequiredInputBufferSizeTest,
+    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
+    &generateTestName);
+INSTANTIATE_TEST_CASE_P(
+    SupportedInputBufferSize, RequiredInputBufferSizeTest,
+    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
+    &generateTestName);
+
+// Test that the recommended capture config are supported or lead to a
+// INVALID_ARGUMENTS return
+class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
+TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) {
+    doc::test(
+        "Input buffer size should be retrievable for a format with recommended "
+        "support.");
+    inputBufferSizeTest(GetParam(), false);
+}
+INSTANTIATE_TEST_CASE_P(
+    RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
+    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
+    &generateTestName);
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// setScreenState ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, setScreenState) {
+    doc::test("Check that the hal can receive the screen state");
+    for (bool turnedOn : {false, true, true, false, false}) {
+        auto ret = device->setScreenState(turnedOn);
+        ASSERT_IS_OK(ret);
+        Result result = ret;
+        auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
+        ASSERT_RESULT(okOrNotSupported, result);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////// {get,set}Parameters /////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, getParameters) {
+    doc::test("Check that the hal can set and get parameters");
+    hidl_vec<hidl_string> keys;
+    hidl_vec<ParameterValue> values;
+    ASSERT_OK(device->getParameters(keys, returnIn(res, values)));
+    ASSERT_OK(device->setParameters(values));
+    values.resize(0);
+    ASSERT_OK(device->setParameters(values));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// debugDebug //////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+template <class DebugDump>
+static void testDebugDump(DebugDump debugDump) {
+    // File descriptors to our pipe. fds[0] corresponds to the read end and
+    // fds[1] to the write end.
+    int fds[2];
+    ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+    // Make sure that the pipe is at least 1 MB in size. The test process runs
+    // in su domain, so it should be safe to make this call.
+    fcntl(fds[0], F_SETPIPE_SZ, 1 << 20);
+
+    // Wrap the temporary file file descriptor in a native handle
+    auto* nativeHandle = native_handle_create(1, 0);
+    ASSERT_NE(nullptr, nativeHandle);
+    nativeHandle->data[0] = fds[1];
+
+    // Wrap this native handle in a hidl handle
+    hidl_handle handle;
+    handle.setTo(nativeHandle, false /*take ownership*/);
+
+    ASSERT_OK(debugDump(handle));
+
+    // Check that at least one bit was written by the hal
+    // TODO: debugDump does not return a Result.
+    // This mean that the hal can not report that it not implementing the
+    // function.
+    char buff;
+    if (read(fds[0], &buff, 1) != 1) {
+        doc::note("debugDump does not seem implemented");
+    }
+    EXPECT_EQ(0, close(fds[0])) << errno;
+    EXPECT_EQ(0, close(fds[1])) << errno;
+}
+
+TEST_F(AudioPrimaryHidlTest, DebugDump) {
+    doc::test("Check that the hal can dump its state without error");
+    testDebugDump([](const auto& handle) { return device->debugDump(handle); });
+}
+
+TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
+    doc::test("Check that the hal dump doesn't crash on invalid arguments");
+    ASSERT_OK(device->debugDump(hidl_handle()));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////// open{Output,Input}Stream //////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+template <class Stream>
+class OpenStreamTest : public AudioConfigPrimaryTest,
+                       public ::testing::WithParamInterface<AudioConfig> {
+   protected:
+    template <class Open>
+    void testOpen(Open openStream, const AudioConfig& config) {
+        // FIXME: Open a stream without an IOHandle
+        //        This is not required to be accepted by hal implementations
+        AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
+        AudioConfig suggestedConfig{};
+        ASSERT_OK(openStream(ioHandle, config, returnIn(res, stream, suggestedConfig)));
+
+        // TODO: only allow failure for RecommendedPlaybackAudioConfig
+        switch (res) {
+            case Result::OK:
+                ASSERT_TRUE(stream != nullptr);
+                audioConfig = config;
+                break;
+            case Result::INVALID_ARGUMENTS:
+                ASSERT_TRUE(stream == nullptr);
+                AudioConfig suggestedConfigRetry;
+                // Could not open stream with config, try again with the
+                // suggested one
+                ASSERT_OK(openStream(ioHandle, suggestedConfig,
+                                     returnIn(res, stream, suggestedConfigRetry)));
+                // This time it must succeed
+                ASSERT_OK(res);
+                ASSERT_TRUE(stream != nullptr);
+                audioConfig = suggestedConfig;
+                break;
+            default:
+                FAIL() << "Invalid return status: " << ::testing::PrintToString(res);
+        }
+        open = true;
+    }
+
+    Return<Result> closeStream() {
+        open = false;
+        return stream->close();
+    }
+
+   private:
+    void TearDown() override {
+        if (open) {
+            ASSERT_OK(stream->close());
+        }
+    }
+
+   protected:
+    AudioConfig audioConfig;
+    DeviceAddress address = {};
+    sp<Stream> stream;
+    bool open = false;
+};
+
+////////////////////////////// openOutputStream //////////////////////////////
+
+class OutputStreamTest : public OpenStreamTest<IStreamOut> {
+    virtual void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
+        address.device = AudioDevice::OUT_DEFAULT;
+        const AudioConfig& config = GetParam();
+        AudioOutputFlag flags = AudioOutputFlag::NONE;  // TODO: test all flag combination
+        testOpen(
+            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                return device->openOutputStream(handle, address, config, flags, cb);
+            },
+            config);
+    }
+};
+TEST_P(OutputStreamTest, OpenOutputStreamTest) {
+    doc::test(
+        "Check that output streams can be open with the required and "
+        "recommended config");
+    // Open done in SetUp
+}
+INSTANTIATE_TEST_CASE_P(
+    RequiredOutputStreamConfigSupport, OutputStreamTest,
+    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
+    &generateTestName);
+INSTANTIATE_TEST_CASE_P(
+    SupportedOutputStreamConfig, OutputStreamTest,
+    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
+    &generateTestName);
+
+INSTANTIATE_TEST_CASE_P(
+    RecommendedOutputStreamConfigSupport, OutputStreamTest,
+    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
+    &generateTestName);
+
+////////////////////////////// openInputStream //////////////////////////////
+
+class InputStreamTest : public OpenStreamTest<IStreamIn> {
+    virtual void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp());  // setup base
+        address.device = AudioDevice::IN_DEFAULT;
+        const AudioConfig& config = GetParam();
+        AudioInputFlag flags = AudioInputFlag::NONE;  // TODO: test all flag combination
+        AudioSource source = AudioSource::DEFAULT;    // TODO: test all flag combination
+        testOpen(
+            [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+                return device->openInputStream(handle, address, config, flags, source, cb);
+            },
+            config);
+    }
+};
+
+TEST_P(InputStreamTest, OpenInputStreamTest) {
+    doc::test(
+        "Check that input streams can be open with the required and "
+        "recommended config");
+    // Open done in setup
+}
+INSTANTIATE_TEST_CASE_P(
+    RequiredInputStreamConfigSupport, InputStreamTest,
+    ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
+    &generateTestName);
+INSTANTIATE_TEST_CASE_P(
+    SupportedInputStreamConfig, InputStreamTest,
+    ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
+    &generateTestName);
+
+INSTANTIATE_TEST_CASE_P(
+    RecommendedInputStreamConfigSupport, InputStreamTest,
+    ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
+    &generateTestName);
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////////// IStream getters ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+/** Unpack the provided result.
+ * If the result is not OK, register a failure and return an undefined value. */
+template <class R>
+static R extract(Return<R> ret) {
+    if (!ret.isOk()) {
+        EXPECT_IS_OK(ret);
+        return R{};
+    }
+    return ret;
+}
+
+/* Could not find a way to write a test for two parametrized class fixure
+ * thus use this macro do duplicate tests for Input and Output stream */
+#define TEST_IO_STREAM(test_name, documentation, code) \
+    TEST_P(InputStreamTest, test_name) {               \
+        doc::test(documentation);                      \
+        code;                                          \
+    }                                                  \
+    TEST_P(OutputStreamTest, test_name) {              \
+        doc::test(documentation);                      \
+        code;                                          \
+    }
+
+TEST_IO_STREAM(GetFrameCount, "Check that the stream frame count == the one it was opened with",
+               ASSERT_EQ(audioConfig.frameCount, extract(stream->getFrameCount())))
+
+TEST_IO_STREAM(GetSampleRate, "Check that the stream sample rate == the one it was opened with",
+               ASSERT_EQ(audioConfig.sampleRateHz, extract(stream->getSampleRate())))
+
+TEST_IO_STREAM(GetChannelMask, "Check that the stream channel mask == the one it was opened with",
+               ASSERT_EQ(audioConfig.channelMask, extract(stream->getChannelMask())))
+
+TEST_IO_STREAM(GetFormat, "Check that the stream format == the one it was opened with",
+               ASSERT_EQ(audioConfig.format, extract(stream->getFormat())))
+
+// TODO: for now only check that the framesize is not incoherent
+TEST_IO_STREAM(GetFrameSize, "Check that the stream frame size == the one it was opened with",
+               ASSERT_GT(extract(stream->getFrameSize()), 0U))
+
+TEST_IO_STREAM(GetBufferSize, "Check that the stream buffer size== the one it was opened with",
+               ASSERT_GE(extract(stream->getBufferSize()), extract(stream->getFrameSize())));
+
+template <class Property, class CapabilityGetter>
+static void testCapabilityGetter(const string& name, IStream* stream,
+                                 CapabilityGetter capablityGetter,
+                                 Return<Property> (IStream::*getter)(),
+                                 Return<Result> (IStream::*setter)(Property),
+                                 bool currentMustBeSupported = true) {
+    hidl_vec<Property> capabilities;
+    ASSERT_OK((stream->*capablityGetter)(returnIn(capabilities)));
+    if (capabilities.size() == 0) {
+        // The default hal should probably return a NOT_SUPPORTED if the hal
+        // does not expose
+        // capability retrieval. For now it returns an empty list if not
+        // implemented
+        doc::partialTest(name + " is not supported");
+        return;
+    };
+
+    if (currentMustBeSupported) {
+        Property currentValue = extract((stream->*getter)());
+        EXPECT_NE(std::find(capabilities.begin(), capabilities.end(), currentValue),
+                  capabilities.end())
+            << "current " << name << " is not in the list of the supported ones "
+            << toString(capabilities);
+    }
+
+    // Check that all declared supported values are indeed supported
+    for (auto capability : capabilities) {
+        auto ret = (stream->*setter)(capability);
+        ASSERT_TRUE(ret.isOk());
+        if (ret == Result::NOT_SUPPORTED) {
+            doc::partialTest("Setter is not supported");
+            return;
+        }
+        ASSERT_OK(ret);
+        ASSERT_EQ(capability, extract((stream->*getter)()));
+    }
+}
+
+TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported",
+               testCapabilityGetter("getSupportedSampleRate", stream.get(),
+                                    &IStream::getSupportedSampleRates, &IStream::getSampleRate,
+                                    &IStream::setSampleRate,
+                                    // getSupportedSampleRate returns the native sampling rates,
+                                    // (the sampling rates that can be played without resampling)
+                                    // but other sampling rates can be supported by the HAL.
+                                    false))
+
+TEST_IO_STREAM(SupportedChannelMask, "Check that the stream channel mask is declared as supported",
+               testCapabilityGetter("getSupportedChannelMask", stream.get(),
+                                    &IStream::getSupportedChannelMasks, &IStream::getChannelMask,
+                                    &IStream::setChannelMask))
+
+TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported",
+               testCapabilityGetter("getSupportedFormat", stream.get(),
+                                    &IStream::getSupportedFormats, &IStream::getFormat,
+                                    &IStream::setFormat))
+
+static void testGetDevice(IStream* stream, AudioDevice expectedDevice) {
+    // Unfortunately the interface does not allow the implementation to return
+    // NOT_SUPPORTED
+    // Thus allow NONE as signaling that the call is not supported.
+    auto ret = stream->getDevice();
+    ASSERT_IS_OK(ret);
+    AudioDevice device = ret;
+    ASSERT_TRUE(device == expectedDevice || device == AudioDevice::NONE)
+        << "Expected: " << ::testing::PrintToString(expectedDevice)
+        << "\n  Actual: " << ::testing::PrintToString(device);
+}
+
+TEST_IO_STREAM(GetDevice, "Check that the stream device == the one it was opened with",
+               areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported")
+                                          : testGetDevice(stream.get(), address.device))
+
+static void testSetDevice(IStream* stream, const DeviceAddress& address) {
+    DeviceAddress otherAddress = address;
+    otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER
+                                                                      : AudioDevice::IN_BUILTIN_MIC;
+    EXPECT_OK(stream->setDevice(otherAddress));
+
+    ASSERT_OK(stream->setDevice(address));  // Go back to the original value
+}
+
+TEST_IO_STREAM(SetDevice, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC",
+               areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported")
+                                          : testSetDevice(stream.get(), address))
+
+static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
+    uint32_t sampleRateHz;
+    AudioChannelMask mask;
+    AudioFormat format;
+
+    stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
+
+    // FIXME: the qcom hal it does not currently negotiate the sampleRate &
+    // channel mask
+    EXPECT_EQ(expectedConfig.sampleRateHz, sampleRateHz);
+    EXPECT_EQ(expectedConfig.channelMask, mask);
+    EXPECT_EQ(expectedConfig.format, format);
+}
+
+TEST_IO_STREAM(GetAudioProperties,
+               "Check that the stream audio properties == the ones it was opened with",
+               testGetAudioProperties(stream.get(), audioConfig))
+
+static void testConnectedState(IStream* stream) {
+    DeviceAddress address = {};
+    using AD = AudioDevice;
+    for (auto device : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
+        address.device = device;
+
+        ASSERT_OK(stream->setConnectedState(address, true));
+        ASSERT_OK(stream->setConnectedState(address, false));
+    }
+}
+TEST_IO_STREAM(SetConnectedState,
+               "Check that the stream can be notified of device connection and "
+               "deconnection",
+               testConnectedState(stream.get()))
+
+static auto invalidArgsOrNotSupportedOrOK = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED,
+                                             Result::OK};
+TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value",
+               ASSERT_RESULT(invalidArgsOrNotSupportedOrOK, stream->setHwAvSync(666)))
+
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync()));
+
+static void checkGetNoParameter(IStream* stream, hidl_vec<hidl_string> keys,
+                                initializer_list<Result> expectedResults) {
+    hidl_vec<ParameterValue> parameters;
+    Result res;
+    ASSERT_OK(stream->getParameters(keys, returnIn(res, parameters)));
+    ASSERT_RESULT(expectedResults, res);
+    if (res == Result::OK) {
+        for (auto& parameter : parameters) {
+            ASSERT_EQ(0U, parameter.value.size()) << toString(parameter);
+        }
+    }
+}
+
+/* Get/Set parameter is intended to be an opaque channel between vendors app and
+ * their HALs.
+ * Thus can not be meaningfully tested.
+ */
+TEST_IO_STREAM(getEmptySetParameter, "Retrieve the values of an empty set",
+               checkGetNoParameter(stream.get(), {} /* keys */, {Result::OK}))
+
+TEST_IO_STREAM(getNonExistingParameter, "Retrieve the values of an non existing parameter",
+               checkGetNoParameter(stream.get(), {"Non existing key"} /* keys */,
+                                   {Result::NOT_SUPPORTED}))
+
+TEST_IO_STREAM(setEmptySetParameter, "Set the values of an empty set of parameters",
+               ASSERT_RESULT(Result::OK, stream->setParameters({})))
+
+TEST_IO_STREAM(setNonExistingParameter, "Set the values of an non existing parameter",
+               // Unfortunately, the set_parameter legacy interface did not return any
+               // error code when a key is not supported.
+               // To allow implementation to just wrapped the legacy one, consider OK as a
+               // valid result for setting a non existing parameter.
+               ASSERT_RESULT(invalidArgsOrNotSupportedOrOK,
+                             stream->setParameters({{"non existing key", "0"}})))
+
+TEST_IO_STREAM(DebugDump, "Check that a stream can dump its state without error",
+               testDebugDump([this](const auto& handle) { return stream->debugDump(handle); }))
+
+TEST_IO_STREAM(DebugDumpInvalidArguments,
+               "Check that the stream dump doesn't crash on invalid arguments",
+               ASSERT_OK(stream->debugDump(hidl_handle())))
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////////// addRemoveEffect ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_IO_STREAM(AddNonExistingEffect, "Adding a non existing effect should fail",
+               ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->addEffect(666)))
+TEST_IO_STREAM(RemoveNonExistingEffect, "Removing a non existing effect should fail",
+               ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->removeEffect(666)))
+
+// TODO: positive tests
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Control ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_IO_STREAM(standby, "Make sure the stream can be put in stanby",
+               ASSERT_OK(stream->standby()))  // can not fail
+
+static constexpr auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED};
+
+TEST_IO_STREAM(startNoMmap, "Starting a mmaped stream before mapping it should fail",
+               ASSERT_RESULT(invalidStateOrNotSupported, stream->start()))
+
+TEST_IO_STREAM(stopNoMmap, "Stopping a mmaped stream before mapping it should fail",
+               ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
+
+TEST_IO_STREAM(getMmapPositionNoMmap, "Get a stream Mmap position before mapping it should fail",
+               ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
+
+TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream()))
+TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice", ASSERT_OK(closeStream());
+               ASSERT_RESULT(Result::INVALID_STATE, closeStream()))
+
+static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED};
+static void testCreateTooBigMmapBuffer(IStream* stream) {
+    MmapBufferInfo info;
+    Result res;
+    // Assume that int max is a value too big to be allocated
+    // This is true currently with a 32bit media server, but might not when it
+    // will run in 64 bit
+    auto minSizeFrames = std::numeric_limits<int32_t>::max();
+    ASSERT_OK(stream->createMmapBuffer(minSizeFrames, returnIn(res, info)));
+    ASSERT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer too big should fail",
+               testCreateTooBigMmapBuffer(stream.get()))
+
+static void testGetMmapPositionOfNonMmapedStream(IStream* stream) {
+    Result res;
+    MmapPosition position;
+    ASSERT_OK(stream->getMmapPosition(returnIn(res, position)));
+    ASSERT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_IO_STREAM(GetMmapPositionOfNonMmapedStream,
+               "Retrieving the mmap position of a non mmaped stream should fail",
+               testGetMmapPositionOfNonMmapedStream(stream.get()))
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// StreamIn ///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_P(InputStreamTest, GetAudioSource) {
+    doc::test("Retrieving the audio source of an input stream should always succeed");
+    AudioSource source;
+    ASSERT_OK(stream->getAudioSource(returnIn(res, source)));
+    if (res == Result::NOT_SUPPORTED) {
+        doc::partialTest("getAudioSource is not supported");
+        return;
+    }
+    ASSERT_OK(res);
+    ASSERT_EQ(AudioSource::DEFAULT, source);
+}
+
+static void testUnitaryGain(std::function<Return<Result>(float)> setGain) {
+    for (float value : (float[]){-INFINITY, -1.0, 1.0 + std::numeric_limits<float>::epsilon(), 2.0,
+                                 INFINITY, NAN}) {
+        EXPECT_RESULT(Result::INVALID_ARGUMENTS, setGain(value)) << "value=" << value;
+    }
+    // Do not consider -0.0 as an invalid value as it is == with 0.0
+    for (float value : {-0.0, 0.0, 0.01, 0.5, 0.09, 1.0 /* Restore volume*/}) {
+        EXPECT_OK(setGain(value)) << "value=" << value;
+    }
+}
+
+static void testOptionalUnitaryGain(std::function<Return<Result>(float)> setGain,
+                                    string debugName) {
+    auto result = setGain(1);
+    ASSERT_IS_OK(result);
+    if (result == Result::NOT_SUPPORTED) {
+        doc::partialTest(debugName + " is not supported");
+        return;
+    }
+    testUnitaryGain(setGain);
+}
+
+TEST_P(InputStreamTest, SetGain) {
+    doc::test("The gain of an input stream should only be set between [0,1]");
+    testOptionalUnitaryGain([this](float volume) { return stream->setGain(volume); },
+                            "InputStream::setGain");
+}
+
+static void testPrepareForReading(IStreamIn* stream, uint32_t frameSize, uint32_t framesCount) {
+    Result res;
+    // Ignore output parameters as the call should fail
+    ASSERT_OK(stream->prepareForReading(frameSize, framesCount,
+                                        [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+    EXPECT_RESULT(Result::INVALID_ARGUMENTS, res);
+}
+
+TEST_P(InputStreamTest, PrepareForReadingWithZeroBuffer) {
+    doc::test("Preparing a stream for reading with a 0 sized buffer should fail");
+    testPrepareForReading(stream.get(), 0, 0);
+}
+
+TEST_P(InputStreamTest, PrepareForReadingWithHugeBuffer) {
+    doc::test("Preparing a stream for reading with a 2^32 sized buffer should fail");
+    testPrepareForReading(stream.get(), 1, std::numeric_limits<uint32_t>::max());
+}
+
+TEST_P(InputStreamTest, PrepareForReadingCheckOverflow) {
+    doc::test(
+        "Preparing a stream for reading with a overflowing sized buffer should "
+        "fail");
+    auto uintMax = std::numeric_limits<uint32_t>::max();
+    testPrepareForReading(stream.get(), uintMax, uintMax);
+}
+
+TEST_P(InputStreamTest, GetInputFramesLost) {
+    doc::test("The number of frames lost on a never started stream should be 0");
+    auto ret = stream->getInputFramesLost();
+    ASSERT_IS_OK(ret);
+    uint32_t framesLost{ret};
+    ASSERT_EQ(0U, framesLost);
+}
+
+TEST_P(InputStreamTest, getCapturePosition) {
+    doc::test(
+        "The capture position of a non prepared stream should not be "
+        "retrievable");
+    uint64_t frames;
+    uint64_t time;
+    ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, time)));
+    ASSERT_RESULT(invalidStateOrNotSupported, res);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// StreamIn ///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_P(OutputStreamTest, getLatency) {
+    doc::test("Make sure latency is over 0");
+    auto result = stream->getLatency();
+    ASSERT_IS_OK(result);
+    ASSERT_GT(result, 0U);
+}
+
+TEST_P(OutputStreamTest, setVolume) {
+    doc::test("Try to set the output volume");
+    testOptionalUnitaryGain([this](float volume) { return stream->setVolume(volume, volume); },
+                            "setVolume");
+}
+
+static void testPrepareForWriting(IStreamOut* stream, uint32_t frameSize, uint32_t framesCount) {
+    Result res;
+    // Ignore output parameters as the call should fail
+    ASSERT_OK(stream->prepareForWriting(frameSize, framesCount,
+                                        [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+    EXPECT_RESULT(Result::INVALID_ARGUMENTS, res);
+}
+
+TEST_P(OutputStreamTest, PrepareForWriteWithZeroBuffer) {
+    doc::test("Preparing a stream for writing with a 0 sized buffer should fail");
+    testPrepareForWriting(stream.get(), 0, 0);
+}
+
+TEST_P(OutputStreamTest, PrepareForWriteWithHugeBuffer) {
+    doc::test("Preparing a stream for writing with a 2^32 sized buffer should fail");
+    testPrepareForWriting(stream.get(), 1, std::numeric_limits<uint32_t>::max());
+}
+
+TEST_P(OutputStreamTest, PrepareForWritingCheckOverflow) {
+    doc::test(
+        "Preparing a stream for writing with a overflowing sized buffer should "
+        "fail");
+    auto uintMax = std::numeric_limits<uint32_t>::max();
+    testPrepareForWriting(stream.get(), uintMax, uintMax);
+}
+
+struct Capability {
+    Capability(IStreamOut* stream) {
+        EXPECT_OK(stream->supportsPauseAndResume(returnIn(pause, resume)));
+        auto ret = stream->supportsDrain();
+        EXPECT_IS_OK(ret);
+        if (ret.isOk()) {
+            drain = ret;
+        }
+    }
+    bool pause = false;
+    bool resume = false;
+    bool drain = false;
+};
+
+TEST_P(OutputStreamTest, SupportsPauseAndResumeAndDrain) {
+    doc::test("Implementation must expose pause, resume and drain capabilities");
+    Capability(stream.get());
+}
+
+template <class Value>
+static void checkInvalidStateOr0(Result res, Value value) {
+    switch (res) {
+        case Result::INVALID_STATE:
+            break;
+        case Result::OK:
+            ASSERT_EQ(0U, value);
+            break;
+        default:
+            FAIL() << "Unexpected result " << toString(res);
+    }
+}
+
+TEST_P(OutputStreamTest, GetRenderPosition) {
+    doc::test("A new stream render position should be 0 or INVALID_STATE");
+    uint32_t dspFrames;
+    ASSERT_OK(stream->getRenderPosition(returnIn(res, dspFrames)));
+    if (res == Result::NOT_SUPPORTED) {
+        doc::partialTest("getRenderPosition is not supported");
+        return;
+    }
+    checkInvalidStateOr0(res, dspFrames);
+}
+
+TEST_P(OutputStreamTest, GetNextWriteTimestamp) {
+    doc::test("A new stream next write timestamp should be 0 or INVALID_STATE");
+    uint64_t timestampUs;
+    ASSERT_OK(stream->getNextWriteTimestamp(returnIn(res, timestampUs)));
+    if (res == Result::NOT_SUPPORTED) {
+        doc::partialTest("getNextWriteTimestamp is not supported");
+        return;
+    }
+    checkInvalidStateOr0(res, timestampUs);
+}
+
+/** Stub implementation of out stream callback. */
+class MockOutCallbacks : public IStreamOutCallback {
+    Return<void> onWriteReady() override { return {}; }
+    Return<void> onDrainReady() override { return {}; }
+    Return<void> onError() override { return {}; }
+};
+
+static bool isAsyncModeSupported(IStreamOut* stream) {
+    auto res = stream->setCallback(new MockOutCallbacks);
+    stream->clearCallback();  // try to restore the no callback state, ignore
+                              // any error
+    auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
+    EXPECT_RESULT(okOrNotSupported, res);
+    return res.isOk() ? res == Result::OK : false;
+}
+
+TEST_P(OutputStreamTest, SetCallback) {
+    doc::test(
+        "If supported, registering callback for async operation should never "
+        "fail");
+    if (!isAsyncModeSupported(stream.get())) {
+        doc::partialTest("The stream does not support async operations");
+        return;
+    }
+    ASSERT_OK(stream->setCallback(new MockOutCallbacks));
+    ASSERT_OK(stream->setCallback(new MockOutCallbacks));
+}
+
+TEST_P(OutputStreamTest, clearCallback) {
+    doc::test(
+        "If supported, clearing a callback to go back to sync operation should "
+        "not fail");
+    if (!isAsyncModeSupported(stream.get())) {
+        doc::partialTest("The stream does not support async operations");
+        return;
+    }
+    // TODO: Clarify if clearing a non existing callback should fail
+    ASSERT_OK(stream->setCallback(new MockOutCallbacks));
+    ASSERT_OK(stream->clearCallback());
+}
+
+TEST_P(OutputStreamTest, Resume) {
+    doc::test(
+        "If supported, a stream should fail to resume if not previously "
+        "paused");
+    if (!Capability(stream.get()).resume) {
+        doc::partialTest("The output stream does not support resume");
+        return;
+    }
+    ASSERT_RESULT(Result::INVALID_STATE, stream->resume());
+}
+
+TEST_P(OutputStreamTest, Pause) {
+    doc::test(
+        "If supported, a stream should fail to pause if not previously "
+        "started");
+    if (!Capability(stream.get()).pause) {
+        doc::partialTest("The output stream does not support pause");
+        return;
+    }
+    ASSERT_RESULT(Result::INVALID_STATE, stream->resume());
+}
+
+static void testDrain(IStreamOut* stream, AudioDrain type) {
+    if (!Capability(stream).drain) {
+        doc::partialTest("The output stream does not support drain");
+        return;
+    }
+    ASSERT_RESULT(Result::OK, stream->drain(type));
+}
+
+TEST_P(OutputStreamTest, DrainAll) {
+    doc::test("If supported, a stream should always succeed to drain");
+    testDrain(stream.get(), AudioDrain::ALL);
+}
+
+TEST_P(OutputStreamTest, DrainEarlyNotify) {
+    doc::test("If supported, a stream should always succeed to drain");
+    testDrain(stream.get(), AudioDrain::EARLY_NOTIFY);
+}
+
+TEST_P(OutputStreamTest, FlushStop) {
+    doc::test("If supported, a stream should always succeed to flush");
+    auto ret = stream->flush();
+    ASSERT_IS_OK(ret);
+    if (ret == Result::NOT_SUPPORTED) {
+        doc::partialTest("Flush is not supported");
+        return;
+    }
+    ASSERT_OK(ret);
+}
+
+TEST_P(OutputStreamTest, GetPresentationPositionStop) {
+    doc::test(
+        "If supported, a stream should always succeed to retrieve the "
+        "presentation position");
+    uint64_t frames;
+    TimeSpec mesureTS;
+    ASSERT_OK(stream->getPresentationPosition(returnIn(res, frames, mesureTS)));
+    if (res == Result::NOT_SUPPORTED) {
+        doc::partialTest("getpresentationPosition is not supported");
+        return;
+    }
+    ASSERT_EQ(0U, frames);
+
+    if (mesureTS.tvNSec == 0 && mesureTS.tvSec == 0) {
+        // As the stream has never written a frame yet,
+        // the timestamp does not really have a meaning, allow to return 0
+        return;
+    }
+
+    // Make sure the return measure is not more than 1s old.
+    struct timespec currentTS;
+    ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &currentTS)) << errno;
+
+    auto toMicroSec = [](uint64_t sec, auto nsec) { return sec * 1e+6 + nsec / 1e+3; };
+    auto currentTime = toMicroSec(currentTS.tv_sec, currentTS.tv_nsec);
+    auto mesureTime = toMicroSec(mesureTS.tvSec, mesureTS.tvNSec);
+    ASSERT_PRED2([](auto c, auto m) { return c - m < 1e+6; }, currentTime, mesureTime);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// PrimaryDevice ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
+    doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
+    testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); });
+}
+
+TEST_F(AudioPrimaryHidlTest, setMode) {
+    doc::test(
+        "Make sure setMode always succeeds if mode is valid "
+        "and fails otherwise");
+    // Test Invalid values
+    for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) {
+        SCOPED_TRACE("mode=" + toString(mode));
+        ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode));
+    }
+    // Test valid values
+    for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
+                           AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
+        SCOPED_TRACE("mode=" + toString(mode));
+        ASSERT_OK(device->setMode(mode));
+    }
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
+    doc::test("Query and set the BT SCO NR&EC state");
+    testOptionalAccessors("BtScoNrecEnabled", {true, false, true},
+                          &IPrimaryDevice::setBtScoNrecEnabled,
+                          &IPrimaryDevice::getBtScoNrecEnabled);
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
+    doc::test("Query and set the SCO whideband state");
+    testOptionalAccessors("BtScoWideband", {true, false, true},
+                          &IPrimaryDevice::setBtScoWidebandEnabled,
+                          &IPrimaryDevice::getBtScoWidebandEnabled);
+}
+
+using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<TtyMode>;
+TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
+    doc::test("Query and set the TTY mode state");
+    testOptionalAccessors("TTY mode", {TtyMode::OFF, TtyMode::HCO, TtyMode::VCO, TtyMode::FULL},
+                          &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
+    doc::test("Query and set the HAC state");
+    testOptionalAccessors("HAC", {true, false, true}, &IPrimaryDevice::setHacEnabled,
+                          &IPrimaryDevice::getHacEnabled);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////// Clean caches on global tear down ////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+int main(int argc, char** argv) {
+    environment = new AudioHidlTestEnvironment;
+    ::testing::AddGlobalTestEnvironment(environment);
+    ::testing::InitGoogleTest(&argc, argv);
+    environment->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    return status;
+}
diff --git a/audio/core/2.0/vts/functional/ValidateAudioConfiguration.cpp b/audio/core/2.0/vts/functional/ValidateAudioConfiguration.cpp
new file mode 100644
index 0000000..bef0e82
--- /dev/null
+++ b/audio/core/2.0/vts/functional/ValidateAudioConfiguration.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <string>
+
+#include "utility/ValidateXml.h"
+
+TEST(CheckConfig, audioPolicyConfigurationValidation) {
+    RecordProperty("description",
+                   "Verify that the audio policy configuration file "
+                   "is valid according to the schema");
+
+    std::vector<const char*> locations = {"/odm/etc", "/vendor/etc", "/system/etc"};
+    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("audio_policy_configuration.xml", locations,
+                                            "/data/local/tmp/audio_policy_configuration.xsd");
+}
diff --git a/audio/common/2.0/default/OWNERS b/audio/core/all-versions/OWNERS
similarity index 100%
copy from audio/common/2.0/default/OWNERS
copy to audio/core/all-versions/OWNERS
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
new file mode 100644
index 0000000..214b8d5
--- /dev/null
+++ b/audio/core/all-versions/default/Android.bp
@@ -0,0 +1,30 @@
+cc_library_headers {
+    name: "android.hardware.audio.core@all-versions-impl",
+    relative_install_path: "hw",
+    proprietary: true,
+    vendor: true,
+
+    defaults: ["hidl_defaults"],
+
+    export_include_dirs: ["include"],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "android.hardware.audio.common-util",
+    ],
+
+    header_libs: [
+        "libaudioclient_headers",
+        "libaudio_system_headers",
+        "libhardware_headers",
+        "libmedia_headers",
+         "android.hardware.audio.common.util@all-versions",
+    ],
+}
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Conversions.h b/audio/core/all-versions/default/include/core/all-versions/default/Conversions.h
new file mode 100644
index 0000000..fa05350
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Conversions.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <string>
+
+#include <system/audio.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress;
+
+std::string deviceAddressToHal(const DeviceAddress& address);
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Conversions.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/Conversions.impl.h
new file mode 100644
index 0000000..3f3f936
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Conversions.impl.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <stdio.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+std::string deviceAddressToHal(const DeviceAddress& address) {
+    // HAL assumes that the address is NUL-terminated.
+    char halAddress[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+    memset(halAddress, 0, sizeof(halAddress));
+    uint32_t halDevice = static_cast<uint32_t>(address.device);
+    const bool isInput = (halDevice & AUDIO_DEVICE_BIT_IN) != 0;
+    if (isInput) halDevice &= ~AUDIO_DEVICE_BIT_IN;
+    if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) ||
+        (isInput && (halDevice & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) != 0)) {
+        snprintf(halAddress, sizeof(halAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
+                 address.address.mac[0], address.address.mac[1], address.address.mac[2],
+                 address.address.mac[3], address.address.mac[4], address.address.mac[5]);
+    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_IP) != 0) ||
+               (isInput && (halDevice & AUDIO_DEVICE_IN_IP) != 0)) {
+        snprintf(halAddress, sizeof(halAddress), "%d.%d.%d.%d", address.address.ipv4[0],
+                 address.address.ipv4[1], address.address.ipv4[2], address.address.ipv4[3]);
+    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_ALL_USB) != 0) ||
+               (isInput && (halDevice & AUDIO_DEVICE_IN_ALL_USB) != 0)) {
+        snprintf(halAddress, sizeof(halAddress), "card=%d;device=%d", address.address.alsa.card,
+                 address.address.alsa.device);
+    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_BUS) != 0) ||
+               (isInput && (halDevice & AUDIO_DEVICE_IN_BUS) != 0)) {
+        snprintf(halAddress, sizeof(halAddress), "%s", address.busAddress.c_str());
+    } else if ((!isInput && (halDevice & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) != 0 ||
+               (isInput && (halDevice & AUDIO_DEVICE_IN_REMOTE_SUBMIX) != 0)) {
+        snprintf(halAddress, sizeof(halAddress), "%s", address.rSubmixAddress.c_str());
+    }
+    return halAddress;
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Device.h b/audio/core/all-versions/default/include/core/all-versions/default/Device.h
new file mode 100644
index 0000000..224823c
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Device.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <memory>
+
+#include <hardware/audio.h>
+#include <media/AudioParameter.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioConfig;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioHwSync;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioInputFlag;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioOutputFlag;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPatchHandle;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPort;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortConfig;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamIn;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Device : public IDevice, public ParametersUtil {
+    explicit Device(audio_hw_device_t* device);
+
+    // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice follow.
+    Return<Result> initCheck() override;
+    Return<Result> setMasterVolume(float volume) override;
+    Return<void> getMasterVolume(getMasterVolume_cb _hidl_cb) override;
+    Return<Result> setMicMute(bool mute) override;
+    Return<void> getMicMute(getMicMute_cb _hidl_cb) override;
+    Return<Result> setMasterMute(bool mute) override;
+    Return<void> getMasterMute(getMasterMute_cb _hidl_cb) override;
+    Return<void> getInputBufferSize(const AudioConfig& config,
+                                    getInputBufferSize_cb _hidl_cb) override;
+    Return<void> openOutputStream(int32_t ioHandle, const DeviceAddress& device,
+                                  const AudioConfig& config, AudioOutputFlag flags,
+                                  openOutputStream_cb _hidl_cb) override;
+    Return<void> openInputStream(int32_t ioHandle, const DeviceAddress& device,
+                                 const AudioConfig& config, AudioInputFlag flags,
+                                 AudioSource source, openInputStream_cb _hidl_cb) override;
+    Return<bool> supportsAudioPatches() override;
+    Return<void> createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
+                                  const hidl_vec<AudioPortConfig>& sinks,
+                                  createAudioPatch_cb _hidl_cb) override;
+    Return<Result> releaseAudioPatch(int32_t patch) override;
+    Return<void> getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override;
+    Return<Result> setAudioPortConfig(const AudioPortConfig& config) override;
+    Return<AudioHwSync> getHwAvSync() override;
+    Return<Result> setScreenState(bool turnedOn) override;
+    Return<void> getParameters(const hidl_vec<hidl_string>& keys,
+                               getParameters_cb _hidl_cb) override;
+    Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
+    Return<void> debugDump(const hidl_handle& fd) override;
+
+    // Utility methods for extending interfaces.
+    Result analyzeStatus(const char* funcName, int status);
+    void closeInputStream(audio_stream_in_t* stream);
+    void closeOutputStream(audio_stream_out_t* stream);
+    audio_hw_device_t* device() const { return mDevice; }
+
+   private:
+    audio_hw_device_t* mDevice;
+
+    virtual ~Device();
+
+    // Methods from ParametersUtil.
+    char* halGetParameters(const char* keys) override;
+    int halSetParameters(const char* keysAndValues) override;
+
+    uint32_t version() const { return mDevice->common.version; }
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h
new file mode 100644
index 0000000..b295082
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h
@@ -0,0 +1,289 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+//#define LOG_NDEBUG 0
+
+#include <memory.h>
+#include <string.h>
+#include <algorithm>
+
+#include <android/log.h>
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::HidlUtils;
+using ::android::hardware::audio::all_versions::implementation::isGainNormalized;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+Device::Device(audio_hw_device_t* device) : mDevice(device) {}
+
+Device::~Device() {
+    int status = audio_hw_device_close(mDevice);
+    ALOGW_IF(status, "Error closing audio hw device %p: %s", mDevice, strerror(-status));
+    mDevice = nullptr;
+}
+
+Result Device::analyzeStatus(const char* funcName, int status) {
+    if (status != 0) {
+        ALOGW("Device %p %s: %s", mDevice, funcName, strerror(-status));
+    }
+    switch (status) {
+        case 0:
+            return Result::OK;
+        case -EINVAL:
+            return Result::INVALID_ARGUMENTS;
+        case -ENODATA:
+            return Result::INVALID_STATE;
+        case -ENODEV:
+            return Result::NOT_INITIALIZED;
+        case -ENOSYS:
+            return Result::NOT_SUPPORTED;
+        default:
+            return Result::INVALID_STATE;
+    }
+}
+
+void Device::closeInputStream(audio_stream_in_t* stream) {
+    mDevice->close_input_stream(mDevice, stream);
+}
+
+void Device::closeOutputStream(audio_stream_out_t* stream) {
+    mDevice->close_output_stream(mDevice, stream);
+}
+
+char* Device::halGetParameters(const char* keys) {
+    return mDevice->get_parameters(mDevice, keys);
+}
+
+int Device::halSetParameters(const char* keysAndValues) {
+    return mDevice->set_parameters(mDevice, keysAndValues);
+}
+
+// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice follow.
+Return<Result> Device::initCheck() {
+    return analyzeStatus("init_check", mDevice->init_check(mDevice));
+}
+
+Return<Result> Device::setMasterVolume(float volume) {
+    if (mDevice->set_master_volume == NULL) {
+        return Result::NOT_SUPPORTED;
+    }
+    if (!isGainNormalized(volume)) {
+        ALOGW("Can not set a master volume (%f) outside [0,1]", volume);
+        return Result::INVALID_ARGUMENTS;
+    }
+    return analyzeStatus("set_master_volume", mDevice->set_master_volume(mDevice, volume));
+}
+
+Return<void> Device::getMasterVolume(getMasterVolume_cb _hidl_cb) {
+    Result retval(Result::NOT_SUPPORTED);
+    float volume = 0;
+    if (mDevice->get_master_volume != NULL) {
+        retval = analyzeStatus("get_master_volume", mDevice->get_master_volume(mDevice, &volume));
+    }
+    _hidl_cb(retval, volume);
+    return Void();
+}
+
+Return<Result> Device::setMicMute(bool mute) {
+    return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute));
+}
+
+Return<void> Device::getMicMute(getMicMute_cb _hidl_cb) {
+    bool mute = false;
+    Result retval = analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute));
+    _hidl_cb(retval, mute);
+    return Void();
+}
+
+Return<Result> Device::setMasterMute(bool mute) {
+    Result retval(Result::NOT_SUPPORTED);
+    if (mDevice->set_master_mute != NULL) {
+        retval = analyzeStatus("set_master_mute", mDevice->set_master_mute(mDevice, mute));
+    }
+    return retval;
+}
+
+Return<void> Device::getMasterMute(getMasterMute_cb _hidl_cb) {
+    Result retval(Result::NOT_SUPPORTED);
+    bool mute = false;
+    if (mDevice->get_master_mute != NULL) {
+        retval = analyzeStatus("get_master_mute", mDevice->get_master_mute(mDevice, &mute));
+    }
+    _hidl_cb(retval, mute);
+    return Void();
+}
+
+Return<void> Device::getInputBufferSize(const AudioConfig& config, getInputBufferSize_cb _hidl_cb) {
+    audio_config_t halConfig;
+    HidlUtils::audioConfigToHal(config, &halConfig);
+    size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig);
+    Result retval(Result::INVALID_ARGUMENTS);
+    uint64_t bufferSize = 0;
+    if (halBufferSize != 0) {
+        retval = Result::OK;
+        bufferSize = halBufferSize;
+    }
+    _hidl_cb(retval, bufferSize);
+    return Void();
+}
+
+Return<void> Device::openOutputStream(int32_t ioHandle, const DeviceAddress& device,
+                                      const AudioConfig& config, AudioOutputFlag flags,
+                                      openOutputStream_cb _hidl_cb) {
+    audio_config_t halConfig;
+    HidlUtils::audioConfigToHal(config, &halConfig);
+    audio_stream_out_t* halStream;
+    ALOGV(
+        "open_output_stream handle: %d devices: %x flags: %#x "
+        "srate: %d format %#x channels %x address %s",
+        ioHandle, static_cast<audio_devices_t>(device.device),
+        static_cast<audio_output_flags_t>(flags), halConfig.sample_rate, halConfig.format,
+        halConfig.channel_mask, deviceAddressToHal(device).c_str());
+    int status =
+        mDevice->open_output_stream(mDevice, ioHandle, static_cast<audio_devices_t>(device.device),
+                                    static_cast<audio_output_flags_t>(flags), &halConfig,
+                                    &halStream, deviceAddressToHal(device).c_str());
+    ALOGV("open_output_stream status %d stream %p", status, halStream);
+    sp<IStreamOut> streamOut;
+    if (status == OK) {
+        streamOut = new StreamOut(this, halStream);
+    }
+    AudioConfig suggestedConfig;
+    HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig);
+    _hidl_cb(analyzeStatus("open_output_stream", status), streamOut, suggestedConfig);
+    return Void();
+}
+
+Return<void> Device::openInputStream(int32_t ioHandle, const DeviceAddress& device,
+                                     const AudioConfig& config, AudioInputFlag flags,
+                                     AudioSource source, openInputStream_cb _hidl_cb) {
+    audio_config_t halConfig;
+    HidlUtils::audioConfigToHal(config, &halConfig);
+    audio_stream_in_t* halStream;
+    ALOGV(
+        "open_input_stream handle: %d devices: %x flags: %#x "
+        "srate: %d format %#x channels %x address %s source %d",
+        ioHandle, static_cast<audio_devices_t>(device.device),
+        static_cast<audio_input_flags_t>(flags), halConfig.sample_rate, halConfig.format,
+        halConfig.channel_mask, deviceAddressToHal(device).c_str(),
+        static_cast<audio_source_t>(source));
+    int status = mDevice->open_input_stream(
+        mDevice, ioHandle, static_cast<audio_devices_t>(device.device), &halConfig, &halStream,
+        static_cast<audio_input_flags_t>(flags), deviceAddressToHal(device).c_str(),
+        static_cast<audio_source_t>(source));
+    ALOGV("open_input_stream status %d stream %p", status, halStream);
+    sp<IStreamIn> streamIn;
+    if (status == OK) {
+        streamIn = new StreamIn(this, halStream);
+    }
+    AudioConfig suggestedConfig;
+    HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig);
+    _hidl_cb(analyzeStatus("open_input_stream", status), streamIn, suggestedConfig);
+    return Void();
+}
+
+Return<bool> Device::supportsAudioPatches() {
+    return version() >= AUDIO_DEVICE_API_VERSION_3_0;
+}
+
+Return<void> Device::createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
+                                      const hidl_vec<AudioPortConfig>& sinks,
+                                      createAudioPatch_cb _hidl_cb) {
+    Result retval(Result::NOT_SUPPORTED);
+    AudioPatchHandle patch = 0;
+    if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+        std::unique_ptr<audio_port_config[]> halSources(HidlUtils::audioPortConfigsToHal(sources));
+        std::unique_ptr<audio_port_config[]> halSinks(HidlUtils::audioPortConfigsToHal(sinks));
+        audio_patch_handle_t halPatch = AUDIO_PATCH_HANDLE_NONE;
+        retval = analyzeStatus("create_audio_patch",
+                               mDevice->create_audio_patch(mDevice, sources.size(), &halSources[0],
+                                                           sinks.size(), &halSinks[0], &halPatch));
+        if (retval == Result::OK) {
+            patch = static_cast<AudioPatchHandle>(halPatch);
+        }
+    }
+    _hidl_cb(retval, patch);
+    return Void();
+}
+
+Return<Result> Device::releaseAudioPatch(int32_t patch) {
+    if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+        return analyzeStatus(
+            "release_audio_patch",
+            mDevice->release_audio_patch(mDevice, static_cast<audio_patch_handle_t>(patch)));
+    }
+    return Result::NOT_SUPPORTED;
+}
+
+Return<void> Device::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
+    audio_port halPort;
+    HidlUtils::audioPortToHal(port, &halPort);
+    Result retval = analyzeStatus("get_audio_port", mDevice->get_audio_port(mDevice, &halPort));
+    AudioPort resultPort = port;
+    if (retval == Result::OK) {
+        HidlUtils::audioPortFromHal(halPort, &resultPort);
+    }
+    _hidl_cb(retval, resultPort);
+    return Void();
+}
+
+Return<Result> Device::setAudioPortConfig(const AudioPortConfig& config) {
+    if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+        struct audio_port_config halPortConfig;
+        HidlUtils::audioPortConfigToHal(config, &halPortConfig);
+        return analyzeStatus("set_audio_port_config",
+                             mDevice->set_audio_port_config(mDevice, &halPortConfig));
+    }
+    return Result::NOT_SUPPORTED;
+}
+
+Return<AudioHwSync> Device::getHwAvSync() {
+    int halHwAvSync;
+    Result retval = getParam(AudioParameter::keyHwAvSync, &halHwAvSync);
+    return retval == Result::OK ? halHwAvSync : AUDIO_HW_SYNC_INVALID;
+}
+
+Return<Result> Device::setScreenState(bool turnedOn) {
+    return setParam(AudioParameter::keyScreenState, turnedOn);
+}
+
+Return<void> Device::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
+    getParametersImpl(keys, _hidl_cb);
+    return Void();
+}
+
+Return<Result> Device::setParameters(const hidl_vec<ParameterValue>& parameters) {
+    return setParametersImpl(parameters);
+}
+
+Return<void> Device::debugDump(const hidl_handle& fd) {
+    if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
+        analyzeStatus("dump", mDevice->dump(mDevice, fd->data[0]));
+    }
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.h b/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.h
new file mode 100644
index 0000000..769adaa
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <hardware/audio.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IDevicesFactory;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct DevicesFactory : public IDevicesFactory {
+    // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IDevicesFactory follow.
+    Return<void> openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) override;
+
+   private:
+    static const char* deviceToString(IDevicesFactory::Device device);
+    static int loadAudioInterface(const char* if_name, audio_hw_device_t** dev);
+};
+
+extern "C" IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name);
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h
new file mode 100644
index 0000000..014b4d8
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <string.h>
+
+#include <android/log.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+// static
+const char* DevicesFactory::deviceToString(IDevicesFactory::Device device) {
+    switch (device) {
+        case IDevicesFactory::Device::PRIMARY:
+            return AUDIO_HARDWARE_MODULE_ID_PRIMARY;
+        case IDevicesFactory::Device::A2DP:
+            return AUDIO_HARDWARE_MODULE_ID_A2DP;
+        case IDevicesFactory::Device::USB:
+            return AUDIO_HARDWARE_MODULE_ID_USB;
+        case IDevicesFactory::Device::R_SUBMIX:
+            return AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX;
+        case IDevicesFactory::Device::STUB:
+            return AUDIO_HARDWARE_MODULE_ID_STUB;
+    }
+    return nullptr;
+}
+
+// static
+int DevicesFactory::loadAudioInterface(const char* if_name, audio_hw_device_t** dev) {
+    const hw_module_t* mod;
+    int rc;
+
+    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
+    if (rc) {
+        ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID,
+              if_name, strerror(-rc));
+        goto out;
+    }
+    rc = audio_hw_device_open(mod, dev);
+    if (rc) {
+        ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID,
+              if_name, strerror(-rc));
+        goto out;
+    }
+    if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
+        ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
+        rc = -EINVAL;
+        audio_hw_device_close(*dev);
+        goto out;
+    }
+    return OK;
+
+out:
+    *dev = NULL;
+    return rc;
+}
+
+// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IDevicesFactory follow.
+Return<void> DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) {
+    audio_hw_device_t* halDevice;
+    Result retval(Result::INVALID_ARGUMENTS);
+    sp<IDevice> result;
+    const char* moduleName = deviceToString(device);
+    if (moduleName != nullptr) {
+        int halStatus = loadAudioInterface(moduleName, &halDevice);
+        if (halStatus == OK) {
+            if (device == IDevicesFactory::Device::PRIMARY) {
+                result = new PrimaryDevice(halDevice);
+            } else {
+                result = new ::android::hardware::audio::AUDIO_HAL_VERSION::implementation::Device(
+                    halDevice);
+            }
+            retval = Result::OK;
+        } else if (halStatus == -EINVAL) {
+            retval = Result::NOT_INITIALIZED;
+        }
+    }
+    _hidl_cb(retval, result);
+    return Void();
+}
+
+IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* /* name */) {
+    return new DevicesFactory();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.h b/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.h
new file mode 100644
index 0000000..df5adee
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <functional>
+#include <memory>
+
+#include <hidl/HidlSupport.h>
+#include <media/AudioParameter.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+class ParametersUtil {
+   public:
+    Result getParam(const char* name, bool* value);
+    Result getParam(const char* name, int* value);
+    Result getParam(const char* name, String8* value);
+    void getParametersImpl(
+        const hidl_vec<hidl_string>& keys,
+        std::function<void(Result retval, const hidl_vec<ParameterValue>& parameters)> cb);
+    std::unique_ptr<AudioParameter> getParams(const AudioParameter& keys);
+    Result setParam(const char* name, bool value);
+    Result setParam(const char* name, int value);
+    Result setParam(const char* name, const char* value);
+    Result setParametersImpl(const hidl_vec<ParameterValue>& parameters);
+    Result setParams(const AudioParameter& param);
+
+   protected:
+    virtual ~ParametersUtil() {}
+
+    virtual char* halGetParameters(const char* keys) = 0;
+    virtual int halSetParameters(const char* keysAndValues) = 0;
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.impl.h
new file mode 100644
index 0000000..a858a48
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/ParametersUtil.impl.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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+/** Converts a status_t in Result according to the rules of AudioParameter::get*
+ * Note: Static method and not private method to avoid leaking status_t dependency
+ */
+static Result getHalStatusToResult(status_t status) {
+    switch (status) {
+        case OK:
+            return Result::OK;
+        case BAD_VALUE:  // Nothing was returned, probably because the HAL does
+                         // not handle it
+            return Result::NOT_SUPPORTED;
+        case INVALID_OPERATION:  // Conversion from string to the requested type
+                                 // failed
+            return Result::INVALID_ARGUMENTS;
+        default:  // Should not happen
+            ALOGW("Unexpected status returned by getParam: %u", status);
+            return Result::INVALID_ARGUMENTS;
+    }
+}
+
+Result ParametersUtil::getParam(const char* name, bool* value) {
+    String8 halValue;
+    Result retval = getParam(name, &halValue);
+    *value = false;
+    if (retval == Result::OK) {
+        if (halValue.empty()) {
+            return Result::NOT_SUPPORTED;
+        }
+        *value = !(halValue == AudioParameter::valueOff);
+    }
+    return retval;
+}
+
+Result ParametersUtil::getParam(const char* name, int* value) {
+    const String8 halName(name);
+    AudioParameter keys;
+    keys.addKey(halName);
+    std::unique_ptr<AudioParameter> params = getParams(keys);
+    return getHalStatusToResult(params->getInt(halName, *value));
+}
+
+Result ParametersUtil::getParam(const char* name, String8* value) {
+    const String8 halName(name);
+    AudioParameter keys;
+    keys.addKey(halName);
+    std::unique_ptr<AudioParameter> params = getParams(keys);
+    return getHalStatusToResult(params->get(halName, *value));
+}
+
+void ParametersUtil::getParametersImpl(
+    const hidl_vec<hidl_string>& keys,
+    std::function<void(Result retval, const hidl_vec<ParameterValue>& parameters)> cb) {
+    AudioParameter halKeys;
+    for (size_t i = 0; i < keys.size(); ++i) {
+        halKeys.addKey(String8(keys[i].c_str()));
+    }
+    std::unique_ptr<AudioParameter> halValues = getParams(halKeys);
+    Result retval =
+        (keys.size() == 0 || halValues->size() != 0) ? Result::OK : Result::NOT_SUPPORTED;
+    hidl_vec<ParameterValue> result;
+    result.resize(halValues->size());
+    String8 halKey, halValue;
+    for (size_t i = 0; i < halValues->size(); ++i) {
+        status_t status = halValues->getAt(i, halKey, halValue);
+        if (status != OK) {
+            result.resize(0);
+            retval = getHalStatusToResult(status);
+            break;
+        }
+        result[i].key = halKey.string();
+        result[i].value = halValue.string();
+    }
+    cb(retval, result);
+}
+
+std::unique_ptr<AudioParameter> ParametersUtil::getParams(const AudioParameter& keys) {
+    String8 paramsAndValues;
+    char* halValues = halGetParameters(keys.keysToString().string());
+    if (halValues != NULL) {
+        paramsAndValues.setTo(halValues);
+        free(halValues);
+    } else {
+        paramsAndValues.clear();
+    }
+    return std::unique_ptr<AudioParameter>(new AudioParameter(paramsAndValues));
+}
+
+Result ParametersUtil::setParam(const char* name, bool value) {
+    AudioParameter param;
+    param.add(String8(name), String8(value ? AudioParameter::valueOn : AudioParameter::valueOff));
+    return setParams(param);
+}
+
+Result ParametersUtil::setParam(const char* name, int value) {
+    AudioParameter param;
+    param.addInt(String8(name), value);
+    return setParams(param);
+}
+
+Result ParametersUtil::setParam(const char* name, const char* value) {
+    AudioParameter param;
+    param.add(String8(name), String8(value));
+    return setParams(param);
+}
+
+Result ParametersUtil::setParametersImpl(const hidl_vec<ParameterValue>& parameters) {
+    AudioParameter params;
+    for (size_t i = 0; i < parameters.size(); ++i) {
+        params.add(String8(parameters[i].key.c_str()), String8(parameters[i].value.c_str()));
+    }
+    return setParams(params);
+}
+
+Result ParametersUtil::setParams(const AudioParameter& param) {
+    int halStatus = halSetParameters(param.toString().string());
+    switch (halStatus) {
+        case OK:
+            return Result::OK;
+        case -EINVAL:
+            return Result::INVALID_ARGUMENTS;
+        case -ENODATA:
+            return Result::INVALID_STATE;
+        case -ENODEV:
+            return Result::NOT_INITIALIZED;
+        // The rest of the API (*::analyseStatus) returns NOT_SUPPORTED
+        // when the legacy API returns -ENOSYS
+        // However the legacy API explicitly state that for get_paramers,
+        // -ENOSYS should be returned if
+        // "the implementation does not accept a parameter change while the
+        //  output is active but the parameter is acceptable otherwise"
+        case -ENOSYS:
+            return Result::INVALID_STATE;
+        default:
+            return Result::INVALID_ARGUMENTS;
+    }
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.h b/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.h
new file mode 100644
index 0000000..240b221
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.h
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioConfig;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioInputFlag;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioOutputFlag;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPort;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioPortConfig;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IPrimaryDevice;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamIn;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct PrimaryDevice : public IPrimaryDevice {
+    explicit PrimaryDevice(audio_hw_device_t* device);
+
+    // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice follow.
+    Return<Result> initCheck() override;
+    Return<Result> setMasterVolume(float volume) override;
+    Return<void> getMasterVolume(getMasterVolume_cb _hidl_cb) override;
+    Return<Result> setMicMute(bool mute) override;
+    Return<void> getMicMute(getMicMute_cb _hidl_cb) override;
+    Return<Result> setMasterMute(bool mute) override;
+    Return<void> getMasterMute(getMasterMute_cb _hidl_cb) override;
+    Return<void> getInputBufferSize(const AudioConfig& config,
+                                    getInputBufferSize_cb _hidl_cb) override;
+    Return<void> openOutputStream(int32_t ioHandle, const DeviceAddress& device,
+                                  const AudioConfig& config, AudioOutputFlag flags,
+                                  openOutputStream_cb _hidl_cb) override;
+    Return<void> openInputStream(int32_t ioHandle, const DeviceAddress& device,
+                                 const AudioConfig& config, AudioInputFlag flags,
+                                 AudioSource source, openInputStream_cb _hidl_cb) override;
+    Return<bool> supportsAudioPatches() override;
+    Return<void> createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
+                                  const hidl_vec<AudioPortConfig>& sinks,
+                                  createAudioPatch_cb _hidl_cb) override;
+    Return<Result> releaseAudioPatch(int32_t patch) override;
+    Return<void> getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) override;
+    Return<Result> setAudioPortConfig(const AudioPortConfig& config) override;
+    Return<AudioHwSync> getHwAvSync() override;
+    Return<Result> setScreenState(bool turnedOn) override;
+    Return<void> getParameters(const hidl_vec<hidl_string>& keys,
+                               getParameters_cb _hidl_cb) override;
+    Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
+    Return<void> debugDump(const hidl_handle& fd) override;
+
+    // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IPrimaryDevice follow.
+    Return<Result> setVoiceVolume(float volume) override;
+    Return<Result> setMode(AudioMode mode) override;
+    Return<void> getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) override;
+    Return<Result> setBtScoNrecEnabled(bool enabled) override;
+    Return<void> getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) override;
+    Return<Result> setBtScoWidebandEnabled(bool enabled) override;
+    Return<void> getTtyMode(getTtyMode_cb _hidl_cb) override;
+    Return<Result> setTtyMode(IPrimaryDevice::TtyMode mode) override;
+    Return<void> getHacEnabled(getHacEnabled_cb _hidl_cb) override;
+    Return<Result> setHacEnabled(bool enabled) override;
+
+   private:
+    sp<Device> mDevice;
+
+    virtual ~PrimaryDevice();
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.impl.h
new file mode 100644
index 0000000..3ce047a
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/PrimaryDevice.impl.h
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+PrimaryDevice::PrimaryDevice(audio_hw_device_t* device) : mDevice(new Device(device)) {}
+
+PrimaryDevice::~PrimaryDevice() {}
+
+// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IDevice follow.
+Return<Result> PrimaryDevice::initCheck() {
+    return mDevice->initCheck();
+}
+
+Return<Result> PrimaryDevice::setMasterVolume(float volume) {
+    return mDevice->setMasterVolume(volume);
+}
+
+Return<void> PrimaryDevice::getMasterVolume(getMasterVolume_cb _hidl_cb) {
+    return mDevice->getMasterVolume(_hidl_cb);
+}
+
+Return<Result> PrimaryDevice::setMicMute(bool mute) {
+    return mDevice->setMicMute(mute);
+}
+
+Return<void> PrimaryDevice::getMicMute(getMicMute_cb _hidl_cb) {
+    return mDevice->getMicMute(_hidl_cb);
+}
+
+Return<Result> PrimaryDevice::setMasterMute(bool mute) {
+    return mDevice->setMasterMute(mute);
+}
+
+Return<void> PrimaryDevice::getMasterMute(getMasterMute_cb _hidl_cb) {
+    return mDevice->getMasterMute(_hidl_cb);
+}
+
+Return<void> PrimaryDevice::getInputBufferSize(const AudioConfig& config,
+                                               getInputBufferSize_cb _hidl_cb) {
+    return mDevice->getInputBufferSize(config, _hidl_cb);
+}
+
+Return<void> PrimaryDevice::openOutputStream(int32_t ioHandle, const DeviceAddress& device,
+                                             const AudioConfig& config, AudioOutputFlag flags,
+                                             openOutputStream_cb _hidl_cb) {
+    return mDevice->openOutputStream(ioHandle, device, config, flags, _hidl_cb);
+}
+
+Return<void> PrimaryDevice::openInputStream(int32_t ioHandle, const DeviceAddress& device,
+                                            const AudioConfig& config, AudioInputFlag flags,
+                                            AudioSource source, openInputStream_cb _hidl_cb) {
+    return mDevice->openInputStream(ioHandle, device, config, flags, source, _hidl_cb);
+}
+
+Return<bool> PrimaryDevice::supportsAudioPatches() {
+    return mDevice->supportsAudioPatches();
+}
+
+Return<void> PrimaryDevice::createAudioPatch(const hidl_vec<AudioPortConfig>& sources,
+                                             const hidl_vec<AudioPortConfig>& sinks,
+                                             createAudioPatch_cb _hidl_cb) {
+    return mDevice->createAudioPatch(sources, sinks, _hidl_cb);
+}
+
+Return<Result> PrimaryDevice::releaseAudioPatch(int32_t patch) {
+    return mDevice->releaseAudioPatch(patch);
+}
+
+Return<void> PrimaryDevice::getAudioPort(const AudioPort& port, getAudioPort_cb _hidl_cb) {
+    return mDevice->getAudioPort(port, _hidl_cb);
+}
+
+Return<Result> PrimaryDevice::setAudioPortConfig(const AudioPortConfig& config) {
+    return mDevice->setAudioPortConfig(config);
+}
+
+Return<AudioHwSync> PrimaryDevice::getHwAvSync() {
+    return mDevice->getHwAvSync();
+}
+
+Return<Result> PrimaryDevice::setScreenState(bool turnedOn) {
+    return mDevice->setScreenState(turnedOn);
+}
+
+Return<void> PrimaryDevice::getParameters(const hidl_vec<hidl_string>& keys,
+                                          getParameters_cb _hidl_cb) {
+    return mDevice->getParameters(keys, _hidl_cb);
+}
+
+Return<Result> PrimaryDevice::setParameters(const hidl_vec<ParameterValue>& parameters) {
+    return mDevice->setParameters(parameters);
+}
+
+Return<void> PrimaryDevice::debugDump(const hidl_handle& fd) {
+    return mDevice->debugDump(fd);
+}
+
+// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IPrimaryDevice follow.
+Return<Result> PrimaryDevice::setVoiceVolume(float volume) {
+    if (!all_versions::implementation::isGainNormalized(volume)) {
+        ALOGW("Can not set a voice volume (%f) outside [0,1]", volume);
+        return Result::INVALID_ARGUMENTS;
+    }
+    return mDevice->analyzeStatus("set_voice_volume",
+                                  mDevice->device()->set_voice_volume(mDevice->device(), volume));
+}
+
+Return<Result> PrimaryDevice::setMode(AudioMode mode) {
+    // INVALID, CURRENT, CNT, MAX are reserved for internal use.
+    // TODO: remove the values from the HIDL interface
+    switch (mode) {
+        case AudioMode::NORMAL:
+        case AudioMode::RINGTONE:
+        case AudioMode::IN_CALL:
+        case AudioMode::IN_COMMUNICATION:
+            break;  // Valid values
+        default:
+            return Result::INVALID_ARGUMENTS;
+    };
+
+    return mDevice->analyzeStatus(
+        "set_mode",
+        mDevice->device()->set_mode(mDevice->device(), static_cast<audio_mode_t>(mode)));
+}
+
+Return<void> PrimaryDevice::getBtScoNrecEnabled(getBtScoNrecEnabled_cb _hidl_cb) {
+    bool enabled;
+    Result retval = mDevice->getParam(AudioParameter::keyBtNrec, &enabled);
+    _hidl_cb(retval, enabled);
+    return Void();
+}
+
+Return<Result> PrimaryDevice::setBtScoNrecEnabled(bool enabled) {
+    return mDevice->setParam(AudioParameter::keyBtNrec, enabled);
+}
+
+Return<void> PrimaryDevice::getBtScoWidebandEnabled(getBtScoWidebandEnabled_cb _hidl_cb) {
+    bool enabled;
+    Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, &enabled);
+    _hidl_cb(retval, enabled);
+    return Void();
+}
+
+Return<Result> PrimaryDevice::setBtScoWidebandEnabled(bool enabled) {
+    return mDevice->setParam(AUDIO_PARAMETER_KEY_BT_SCO_WB, enabled);
+}
+
+Return<void> PrimaryDevice::getTtyMode(getTtyMode_cb _hidl_cb) {
+    int halMode;
+    Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_TTY_MODE, &halMode);
+    TtyMode mode = retval == Result::OK ? TtyMode(halMode) : TtyMode::OFF;
+    _hidl_cb(retval, mode);
+    return Void();
+}
+
+Return<Result> PrimaryDevice::setTtyMode(IPrimaryDevice::TtyMode mode) {
+    return mDevice->setParam(AUDIO_PARAMETER_KEY_TTY_MODE, static_cast<int>(mode));
+}
+
+Return<void> PrimaryDevice::getHacEnabled(getHacEnabled_cb _hidl_cb) {
+    bool enabled;
+    Result retval = mDevice->getParam(AUDIO_PARAMETER_KEY_HAC, &enabled);
+    _hidl_cb(retval, enabled);
+    return Void();
+}
+
+Return<Result> PrimaryDevice::setHacEnabled(bool enabled) {
+    return mDevice->setParam(AUDIO_PARAMETER_KEY_HAC, enabled);
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Stream.h b/audio/core/all-versions/default/include/core/all-versions/default/Stream.h
new file mode 100644
index 0000000..4196dec
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Stream.h
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <vector>
+
+#include <hardware/audio.h>
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioFormat;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IStream;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Stream : public IStream, public ParametersUtil {
+    explicit Stream(audio_stream_t* stream);
+
+    /** 1GiB is the maximum buffer size the HAL client is allowed to request.
+     * This value has been chosen to be under SIZE_MAX and still big enough
+     * for all audio use case.
+     * Keep private for 2.0, put in .hal in 2.1
+     */
+    static constexpr uint32_t MAX_BUFFER_SIZE = 2 << 30 /* == 1GiB */;
+
+    // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow.
+    Return<uint64_t> getFrameSize() override;
+    Return<uint64_t> getFrameCount() override;
+    Return<uint64_t> getBufferSize() override;
+    Return<uint32_t> getSampleRate() override;
+    Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override;
+    Return<Result> setSampleRate(uint32_t sampleRateHz) override;
+    Return<AudioChannelMask> getChannelMask() override;
+    Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override;
+    Return<Result> setChannelMask(AudioChannelMask mask) override;
+    Return<AudioFormat> getFormat() override;
+    Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb) override;
+    Return<Result> setFormat(AudioFormat format) override;
+    Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb) override;
+    Return<Result> addEffect(uint64_t effectId) override;
+    Return<Result> removeEffect(uint64_t effectId) override;
+    Return<Result> standby() override;
+    Return<AudioDevice> getDevice() override;
+    Return<Result> setDevice(const DeviceAddress& address) override;
+    Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override;
+    Return<Result> setHwAvSync(uint32_t hwAvSync) override;
+    Return<void> getParameters(const hidl_vec<hidl_string>& keys,
+                               getParameters_cb _hidl_cb) override;
+    Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
+    Return<void> debugDump(const hidl_handle& fd) override;
+    Return<Result> start() override;
+    Return<Result> stop() override;
+    Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
+    Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
+    Return<Result> close() override;
+
+    // Utility methods for extending interfaces.
+    static Result analyzeStatus(const char* funcName, int status);
+    static Result analyzeStatus(const char* funcName, int status,
+                                const std::vector<int>& ignoreErrors);
+
+   private:
+    audio_stream_t* mStream;
+
+    virtual ~Stream();
+
+    // Methods from ParametersUtil.
+    char* halGetParameters(const char* keys) override;
+    int halSetParameters(const char* keysAndValues) override;
+};
+
+template <typename T>
+struct StreamMmap : public RefBase {
+    explicit StreamMmap(T* stream) : mStream(stream) {}
+
+    Return<Result> start();
+    Return<Result> stop();
+    Return<void> createMmapBuffer(int32_t minSizeFrames, size_t frameSize,
+                                  IStream::createMmapBuffer_cb _hidl_cb);
+    Return<void> getMmapPosition(IStream::getMmapPosition_cb _hidl_cb);
+
+   private:
+    StreamMmap() {}
+
+    T* mStream;
+};
+
+template <typename T>
+Return<Result> StreamMmap<T>::start() {
+    if (mStream->start == NULL) return Result::NOT_SUPPORTED;
+    int result = mStream->start(mStream);
+    return Stream::analyzeStatus("start", result);
+}
+
+template <typename T>
+Return<Result> StreamMmap<T>::stop() {
+    if (mStream->stop == NULL) return Result::NOT_SUPPORTED;
+    int result = mStream->stop(mStream);
+    return Stream::analyzeStatus("stop", result);
+}
+
+template <typename T>
+Return<void> StreamMmap<T>::createMmapBuffer(int32_t minSizeFrames, size_t frameSize,
+                                             IStream::createMmapBuffer_cb _hidl_cb) {
+    Result retval(Result::NOT_SUPPORTED);
+    MmapBufferInfo info;
+    native_handle_t* hidlHandle = nullptr;
+
+    if (mStream->create_mmap_buffer != NULL) {
+        struct audio_mmap_buffer_info halInfo;
+        retval = Stream::analyzeStatus(
+            "create_mmap_buffer", mStream->create_mmap_buffer(mStream, minSizeFrames, &halInfo));
+        if (retval == Result::OK) {
+            hidlHandle = native_handle_create(1, 0);
+            hidlHandle->data[0] = halInfo.shared_memory_fd;
+            info.sharedMemory =
+                hidl_memory("audio_buffer", hidlHandle, frameSize * halInfo.buffer_size_frames);
+            info.bufferSizeFrames = halInfo.buffer_size_frames;
+            info.burstSizeFrames = halInfo.burst_size_frames;
+        }
+    }
+    _hidl_cb(retval, info);
+    if (hidlHandle != nullptr) {
+        native_handle_delete(hidlHandle);
+    }
+    return Void();
+}
+
+template <typename T>
+Return<void> StreamMmap<T>::getMmapPosition(IStream::getMmapPosition_cb _hidl_cb) {
+    Result retval(Result::NOT_SUPPORTED);
+    MmapPosition position;
+
+    if (mStream->get_mmap_position != NULL) {
+        struct audio_mmap_position halPosition;
+        retval = Stream::analyzeStatus("get_mmap_position",
+                                       mStream->get_mmap_position(mStream, &halPosition));
+        if (retval == Result::OK) {
+            position.timeNanoseconds = halPosition.time_nanoseconds;
+            position.positionFrames = halPosition.position_frames;
+        }
+    }
+    _hidl_cb(retval, position);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Stream.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/Stream.impl.h
new file mode 100644
index 0000000..92cff72
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Stream.impl.h
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <inttypes.h>
+
+#include <android/log.h>
+#include <hardware/audio.h>
+#include <hardware/audio_effect.h>
+#include <media/TypeConverter.h>
+#include <utils/SortedVector.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+Stream::Stream(audio_stream_t* stream) : mStream(stream) {}
+
+Stream::~Stream() {
+    mStream = nullptr;
+}
+
+// static
+Result Stream::analyzeStatus(const char* funcName, int status) {
+    static const std::vector<int> empty;
+    return analyzeStatus(funcName, status, empty);
+}
+
+template <typename T>
+inline bool element_in(T e, const std::vector<T>& v) {
+    return std::find(v.begin(), v.end(), e) != v.end();
+}
+
+// static
+Result Stream::analyzeStatus(const char* funcName, int status,
+                             const std::vector<int>& ignoreErrors) {
+    if (status != 0 && (ignoreErrors.empty() || !element_in(-status, ignoreErrors))) {
+        ALOGW("Error from HAL stream in function %s: %s", funcName, strerror(-status));
+    }
+    switch (status) {
+        case 0:
+            return Result::OK;
+        case -EINVAL:
+            return Result::INVALID_ARGUMENTS;
+        case -ENODATA:
+            return Result::INVALID_STATE;
+        case -ENODEV:
+            return Result::NOT_INITIALIZED;
+        case -ENOSYS:
+            return Result::NOT_SUPPORTED;
+        default:
+            return Result::INVALID_STATE;
+    }
+}
+
+char* Stream::halGetParameters(const char* keys) {
+    return mStream->get_parameters(mStream, keys);
+}
+
+int Stream::halSetParameters(const char* keysAndValues) {
+    return mStream->set_parameters(mStream, keysAndValues);
+}
+
+// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow.
+Return<uint64_t> Stream::getFrameSize() {
+    // Needs to be implemented by interface subclasses. But can't be declared as pure virtual,
+    // since interface subclasses implementation do not inherit from this class.
+    LOG_ALWAYS_FATAL("Stream::getFrameSize is pure abstract");
+    return uint64_t{};
+}
+
+Return<uint64_t> Stream::getFrameCount() {
+    int halFrameCount;
+    Result retval = getParam(AudioParameter::keyFrameCount, &halFrameCount);
+    return retval == Result::OK ? halFrameCount : 0;
+}
+
+Return<uint64_t> Stream::getBufferSize() {
+    return mStream->get_buffer_size(mStream);
+}
+
+Return<uint32_t> Stream::getSampleRate() {
+    return mStream->get_sample_rate(mStream);
+}
+
+Return<void> Stream::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
+    String8 halListValue;
+    Result result = getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue);
+    hidl_vec<uint32_t> sampleRates;
+    SortedVector<uint32_t> halSampleRates;
+    if (result == Result::OK) {
+        halSampleRates =
+            samplingRatesFromString(halListValue.string(), AudioParameter::valueListSeparator);
+        sampleRates.setToExternal(halSampleRates.editArray(), halSampleRates.size());
+    }
+    _hidl_cb(sampleRates);
+    return Void();
+}
+
+Return<Result> Stream::setSampleRate(uint32_t sampleRateHz) {
+    return setParam(AudioParameter::keySamplingRate, static_cast<int>(sampleRateHz));
+}
+
+Return<AudioChannelMask> Stream::getChannelMask() {
+    return AudioChannelMask(mStream->get_channels(mStream));
+}
+
+Return<void> Stream::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
+    String8 halListValue;
+    Result result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue);
+    hidl_vec<AudioChannelMask> channelMasks;
+    SortedVector<audio_channel_mask_t> halChannelMasks;
+    if (result == Result::OK) {
+        halChannelMasks =
+            channelMasksFromString(halListValue.string(), AudioParameter::valueListSeparator);
+        channelMasks.resize(halChannelMasks.size());
+        for (size_t i = 0; i < halChannelMasks.size(); ++i) {
+            channelMasks[i] = AudioChannelMask(halChannelMasks[i]);
+        }
+    }
+    _hidl_cb(channelMasks);
+    return Void();
+}
+
+Return<Result> Stream::setChannelMask(AudioChannelMask mask) {
+    return setParam(AudioParameter::keyChannels, static_cast<int>(mask));
+}
+
+Return<AudioFormat> Stream::getFormat() {
+    return AudioFormat(mStream->get_format(mStream));
+}
+
+Return<void> Stream::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
+    String8 halListValue;
+    Result result = getParam(AudioParameter::keyStreamSupportedFormats, &halListValue);
+    hidl_vec<AudioFormat> formats;
+    Vector<audio_format_t> halFormats;
+    if (result == Result::OK) {
+        halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator);
+        formats.resize(halFormats.size());
+        for (size_t i = 0; i < halFormats.size(); ++i) {
+            formats[i] = AudioFormat(halFormats[i]);
+        }
+    }
+    _hidl_cb(formats);
+    return Void();
+}
+
+Return<Result> Stream::setFormat(AudioFormat format) {
+    return setParam(AudioParameter::keyFormat, static_cast<int>(format));
+}
+
+Return<void> Stream::getAudioProperties(getAudioProperties_cb _hidl_cb) {
+    uint32_t halSampleRate = mStream->get_sample_rate(mStream);
+    audio_channel_mask_t halMask = mStream->get_channels(mStream);
+    audio_format_t halFormat = mStream->get_format(mStream);
+    _hidl_cb(halSampleRate, AudioChannelMask(halMask), AudioFormat(halFormat));
+    return Void();
+}
+
+Return<Result> Stream::addEffect(uint64_t effectId) {
+    effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
+    if (halEffect != NULL) {
+        return analyzeStatus("add_audio_effect", mStream->add_audio_effect(mStream, halEffect));
+    } else {
+        ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId);
+        return Result::INVALID_ARGUMENTS;
+    }
+}
+
+Return<Result> Stream::removeEffect(uint64_t effectId) {
+    effect_handle_t halEffect = EffectMap::getInstance().get(effectId);
+    if (halEffect != NULL) {
+        return analyzeStatus("remove_audio_effect",
+                             mStream->remove_audio_effect(mStream, halEffect));
+    } else {
+        ALOGW("Invalid effect ID passed from client: %" PRIu64, effectId);
+        return Result::INVALID_ARGUMENTS;
+    }
+}
+
+Return<Result> Stream::standby() {
+    return analyzeStatus("standby", mStream->standby(mStream));
+}
+
+Return<AudioDevice> Stream::getDevice() {
+    int device;
+    Result retval = getParam(AudioParameter::keyRouting, &device);
+    return retval == Result::OK ? static_cast<AudioDevice>(device) : AudioDevice::NONE;
+}
+
+Return<Result> Stream::setDevice(const DeviceAddress& address) {
+    char* halDeviceAddress = audio_device_address_to_parameter(
+        static_cast<audio_devices_t>(address.device), deviceAddressToHal(address).c_str());
+    AudioParameter params((String8(halDeviceAddress)));
+    free(halDeviceAddress);
+    params.addInt(String8(AudioParameter::keyRouting),
+                  static_cast<audio_devices_t>(address.device));
+    return setParams(params);
+}
+
+Return<Result> Stream::setConnectedState(const DeviceAddress& address, bool connected) {
+    return setParam(
+        connected ? AudioParameter::keyStreamConnect : AudioParameter::keyStreamDisconnect,
+        deviceAddressToHal(address).c_str());
+}
+
+Return<Result> Stream::setHwAvSync(uint32_t hwAvSync) {
+    return setParam(AudioParameter::keyStreamHwAvSync, static_cast<int>(hwAvSync));
+}
+
+Return<void> Stream::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
+    getParametersImpl(keys, _hidl_cb);
+    return Void();
+}
+
+Return<Result> Stream::setParameters(const hidl_vec<ParameterValue>& parameters) {
+    return setParametersImpl(parameters);
+}
+
+Return<void> Stream::debugDump(const hidl_handle& fd) {
+    if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
+        analyzeStatus("dump", mStream->dump(mStream, fd->data[0]));
+    }
+    return Void();
+}
+
+Return<Result> Stream::start() {
+    return Result::NOT_SUPPORTED;
+}
+
+Return<Result> Stream::stop() {
+    return Result::NOT_SUPPORTED;
+}
+
+Return<void> Stream::createMmapBuffer(int32_t minSizeFrames __unused,
+                                      createMmapBuffer_cb _hidl_cb) {
+    Result retval(Result::NOT_SUPPORTED);
+    MmapBufferInfo info;
+    _hidl_cb(retval, info);
+    return Void();
+}
+
+Return<void> Stream::getMmapPosition(getMmapPosition_cb _hidl_cb) {
+    Result retval(Result::NOT_SUPPORTED);
+    MmapPosition position;
+    _hidl_cb(retval, position);
+    return Void();
+}
+
+Return<Result> Stream::close() {
+    return Result::NOT_SUPPORTED;
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.h b/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.h
new file mode 100644
index 0000000..7380dae
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.h
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <atomic>
+#include <memory>
+
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <utils/Thread.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioFormat;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IStream;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamIn;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct StreamIn : public IStreamIn {
+    typedef MessageQueue<ReadParameters, kSynchronizedReadWrite> CommandMQ;
+    typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
+    typedef MessageQueue<ReadStatus, kSynchronizedReadWrite> StatusMQ;
+
+    StreamIn(const sp<Device>& device, audio_stream_in_t* stream);
+
+    // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow.
+    Return<uint64_t> getFrameSize() override;
+    Return<uint64_t> getFrameCount() override;
+    Return<uint64_t> getBufferSize() override;
+    Return<uint32_t> getSampleRate() override;
+    Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override;
+    Return<Result> setSampleRate(uint32_t sampleRateHz) override;
+    Return<AudioChannelMask> getChannelMask() override;
+    Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override;
+    Return<Result> setChannelMask(AudioChannelMask mask) override;
+    Return<AudioFormat> getFormat() override;
+    Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb) override;
+    Return<Result> setFormat(AudioFormat format) override;
+    Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb) override;
+    Return<Result> addEffect(uint64_t effectId) override;
+    Return<Result> removeEffect(uint64_t effectId) override;
+    Return<Result> standby() override;
+    Return<AudioDevice> getDevice() override;
+    Return<Result> setDevice(const DeviceAddress& address) override;
+    Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override;
+    Return<Result> setHwAvSync(uint32_t hwAvSync) override;
+    Return<void> getParameters(const hidl_vec<hidl_string>& keys,
+                               getParameters_cb _hidl_cb) override;
+    Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
+    Return<void> debugDump(const hidl_handle& fd) override;
+    Return<Result> close() override;
+
+    // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamIn follow.
+    Return<void> getAudioSource(getAudioSource_cb _hidl_cb) override;
+    Return<Result> setGain(float gain) override;
+    Return<void> prepareForReading(uint32_t frameSize, uint32_t framesCount,
+                                   prepareForReading_cb _hidl_cb) override;
+    Return<uint32_t> getInputFramesLost() override;
+    Return<void> getCapturePosition(getCapturePosition_cb _hidl_cb) override;
+    Return<Result> start() override;
+    Return<Result> stop() override;
+    Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
+    Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
+
+    static Result getCapturePositionImpl(audio_stream_in_t* stream, uint64_t* frames,
+                                         uint64_t* time);
+
+   private:
+    bool mIsClosed;
+    const sp<Device> mDevice;
+    audio_stream_in_t* mStream;
+    const sp<Stream> mStreamCommon;
+    const sp<StreamMmap<audio_stream_in_t>> mStreamMmap;
+    std::unique_ptr<CommandMQ> mCommandMQ;
+    std::unique_ptr<DataMQ> mDataMQ;
+    std::unique_ptr<StatusMQ> mStatusMQ;
+    EventFlag* mEfGroup;
+    std::atomic<bool> mStopReadThread;
+    sp<Thread> mReadThread;
+
+    virtual ~StreamIn();
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.impl.h
new file mode 100644
index 0000000..abee225
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/StreamIn.impl.h
@@ -0,0 +1,422 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include <android/log.h>
+#include <hardware/audio.h>
+#include <utils/Trace.h>
+#include <memory>
+
+using ::android::hardware::audio::AUDIO_HAL_VERSION::MessageQueueFlagBits;
+using ::android::hardware::audio::all_versions::implementation::isGainNormalized;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::ThreadInfo;
+
+namespace {
+
+class ReadThread : public Thread {
+   public:
+    // ReadThread's lifespan never exceeds StreamIn's lifespan.
+    ReadThread(std::atomic<bool>* stop, audio_stream_in_t* stream, StreamIn::CommandMQ* commandMQ,
+               StreamIn::DataMQ* dataMQ, StreamIn::StatusMQ* statusMQ, EventFlag* efGroup)
+        : Thread(false /*canCallJava*/),
+          mStop(stop),
+          mStream(stream),
+          mCommandMQ(commandMQ),
+          mDataMQ(dataMQ),
+          mStatusMQ(statusMQ),
+          mEfGroup(efGroup),
+          mBuffer(nullptr) {}
+    bool init() {
+        mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
+        return mBuffer != nullptr;
+    }
+    virtual ~ReadThread() {}
+
+   private:
+    std::atomic<bool>* mStop;
+    audio_stream_in_t* mStream;
+    StreamIn::CommandMQ* mCommandMQ;
+    StreamIn::DataMQ* mDataMQ;
+    StreamIn::StatusMQ* mStatusMQ;
+    EventFlag* mEfGroup;
+    std::unique_ptr<uint8_t[]> mBuffer;
+    IStreamIn::ReadParameters mParameters;
+    IStreamIn::ReadStatus mStatus;
+
+    bool threadLoop() override;
+
+    void doGetCapturePosition();
+    void doRead();
+};
+
+void ReadThread::doRead() {
+    size_t availableToWrite = mDataMQ->availableToWrite();
+    size_t requestedToRead = mParameters.params.read;
+    if (requestedToRead > availableToWrite) {
+        ALOGW(
+            "truncating read data from %d to %d due to insufficient data queue "
+            "space",
+            (int32_t)requestedToRead, (int32_t)availableToWrite);
+        requestedToRead = availableToWrite;
+    }
+    ssize_t readResult = mStream->read(mStream, &mBuffer[0], requestedToRead);
+    mStatus.retval = Result::OK;
+    if (readResult >= 0) {
+        mStatus.reply.read = readResult;
+        if (!mDataMQ->write(&mBuffer[0], readResult)) {
+            ALOGW("data message queue write failed");
+        }
+    } else {
+        mStatus.retval = Stream::analyzeStatus("read", readResult);
+    }
+}
+
+void ReadThread::doGetCapturePosition() {
+    mStatus.retval = StreamIn::getCapturePositionImpl(
+        mStream, &mStatus.reply.capturePosition.frames, &mStatus.reply.capturePosition.time);
+}
+
+bool ReadThread::threadLoop() {
+    // This implementation doesn't return control back to the Thread until it
+    // decides to stop,
+    // as the Thread uses mutexes, and this can lead to priority inversion.
+    while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+        uint32_t efState = 0;
+        mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState);
+        if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
+            continue;  // Nothing to do.
+        }
+        if (!mCommandMQ->read(&mParameters)) {
+            continue;  // Nothing to do.
+        }
+        mStatus.replyTo = mParameters.command;
+        switch (mParameters.command) {
+            case IStreamIn::ReadCommand::READ:
+                doRead();
+                break;
+            case IStreamIn::ReadCommand::GET_CAPTURE_POSITION:
+                doGetCapturePosition();
+                break;
+            default:
+                ALOGE("Unknown read thread command code %d", mParameters.command);
+                mStatus.retval = Result::NOT_SUPPORTED;
+                break;
+        }
+        if (!mStatusMQ->write(&mStatus)) {
+            ALOGW("status message queue write failed");
+        }
+        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
+    }
+
+    return false;
+}
+
+}  // namespace
+
+StreamIn::StreamIn(const sp<Device>& device, audio_stream_in_t* stream)
+    : mIsClosed(false),
+      mDevice(device),
+      mStream(stream),
+      mStreamCommon(new Stream(&stream->common)),
+      mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
+      mEfGroup(nullptr),
+      mStopReadThread(false) {}
+
+StreamIn::~StreamIn() {
+    ATRACE_CALL();
+    close();
+    if (mReadThread.get()) {
+        ATRACE_NAME("mReadThread->join");
+        status_t status = mReadThread->join();
+        ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
+    }
+    if (mEfGroup) {
+        status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+        ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
+    }
+    mDevice->closeInputStream(mStream);
+    mStream = nullptr;
+}
+
+// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow.
+Return<uint64_t> StreamIn::getFrameSize() {
+    return audio_stream_in_frame_size(mStream);
+}
+
+Return<uint64_t> StreamIn::getFrameCount() {
+    return mStreamCommon->getFrameCount();
+}
+
+Return<uint64_t> StreamIn::getBufferSize() {
+    return mStreamCommon->getBufferSize();
+}
+
+Return<uint32_t> StreamIn::getSampleRate() {
+    return mStreamCommon->getSampleRate();
+}
+
+Return<void> StreamIn::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
+    return mStreamCommon->getSupportedSampleRates(_hidl_cb);
+}
+
+Return<Result> StreamIn::setSampleRate(uint32_t sampleRateHz) {
+    return mStreamCommon->setSampleRate(sampleRateHz);
+}
+
+Return<AudioChannelMask> StreamIn::getChannelMask() {
+    return mStreamCommon->getChannelMask();
+}
+
+Return<void> StreamIn::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
+    return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
+}
+
+Return<Result> StreamIn::setChannelMask(AudioChannelMask mask) {
+    return mStreamCommon->setChannelMask(mask);
+}
+
+Return<AudioFormat> StreamIn::getFormat() {
+    return mStreamCommon->getFormat();
+}
+
+Return<void> StreamIn::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
+    return mStreamCommon->getSupportedFormats(_hidl_cb);
+}
+
+Return<Result> StreamIn::setFormat(AudioFormat format) {
+    return mStreamCommon->setFormat(format);
+}
+
+Return<void> StreamIn::getAudioProperties(getAudioProperties_cb _hidl_cb) {
+    return mStreamCommon->getAudioProperties(_hidl_cb);
+}
+
+Return<Result> StreamIn::addEffect(uint64_t effectId) {
+    return mStreamCommon->addEffect(effectId);
+}
+
+Return<Result> StreamIn::removeEffect(uint64_t effectId) {
+    return mStreamCommon->removeEffect(effectId);
+}
+
+Return<Result> StreamIn::standby() {
+    return mStreamCommon->standby();
+}
+
+Return<AudioDevice> StreamIn::getDevice() {
+    return mStreamCommon->getDevice();
+}
+
+Return<Result> StreamIn::setDevice(const DeviceAddress& address) {
+    return mStreamCommon->setDevice(address);
+}
+
+Return<Result> StreamIn::setConnectedState(const DeviceAddress& address, bool connected) {
+    return mStreamCommon->setConnectedState(address, connected);
+}
+
+Return<Result> StreamIn::setHwAvSync(uint32_t hwAvSync) {
+    return mStreamCommon->setHwAvSync(hwAvSync);
+}
+
+Return<void> StreamIn::getParameters(const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) {
+    return mStreamCommon->getParameters(keys, _hidl_cb);
+}
+
+Return<Result> StreamIn::setParameters(const hidl_vec<ParameterValue>& parameters) {
+    return mStreamCommon->setParameters(parameters);
+}
+
+Return<void> StreamIn::debugDump(const hidl_handle& fd) {
+    return mStreamCommon->debugDump(fd);
+}
+
+Return<Result> StreamIn::start() {
+    return mStreamMmap->start();
+}
+
+Return<Result> StreamIn::stop() {
+    return mStreamMmap->stop();
+}
+
+Return<void> StreamIn::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
+    return mStreamMmap->createMmapBuffer(minSizeFrames, audio_stream_in_frame_size(mStream),
+                                         _hidl_cb);
+}
+
+Return<void> StreamIn::getMmapPosition(getMmapPosition_cb _hidl_cb) {
+    return mStreamMmap->getMmapPosition(_hidl_cb);
+}
+
+Return<Result> StreamIn::close() {
+    if (mIsClosed) return Result::INVALID_STATE;
+    mIsClosed = true;
+    if (mReadThread.get()) {
+        mStopReadThread.store(true, std::memory_order_release);
+    }
+    if (mEfGroup) {
+        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
+    }
+    return Result::OK;
+}
+
+// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamIn follow.
+Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
+    int halSource;
+    Result retval = mStreamCommon->getParam(AudioParameter::keyInputSource, &halSource);
+    AudioSource source(AudioSource::DEFAULT);
+    if (retval == Result::OK) {
+        source = AudioSource(halSource);
+    }
+    _hidl_cb(retval, source);
+    return Void();
+}
+
+Return<Result> StreamIn::setGain(float gain) {
+    if (!isGainNormalized(gain)) {
+        ALOGW("Can not set a stream input gain (%f) outside [0,1]", gain);
+        return Result::INVALID_ARGUMENTS;
+    }
+    return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
+}
+
+Return<void> StreamIn::prepareForReading(uint32_t frameSize, uint32_t framesCount,
+                                         prepareForReading_cb _hidl_cb) {
+    status_t status;
+    ThreadInfo threadInfo = {0, 0};
+
+    // Wrap the _hidl_cb to return an error
+    auto sendError = [&threadInfo, &_hidl_cb](Result result) {
+        _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(),
+                 threadInfo);
+
+    };
+
+    // Create message queues.
+    if (mDataMQ) {
+        ALOGE("the client attempts to call prepareForReading twice");
+        sendError(Result::INVALID_STATE);
+        return Void();
+    }
+    std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
+
+    // Check frameSize and framesCount
+    if (frameSize == 0 || framesCount == 0) {
+        ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize, framesCount);
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+
+    if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) {
+        ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount,
+              Stream::MAX_BUFFER_SIZE);
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+    std::unique_ptr<DataMQ> tempDataMQ(new DataMQ(frameSize * framesCount, true /* EventFlag */));
+
+    std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
+    if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
+        ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
+        ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
+        ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+    EventFlag* tempRawEfGroup{};
+    status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &tempRawEfGroup);
+    std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup(
+        tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); });
+    if (status != OK || !tempElfGroup) {
+        ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+
+    // Create and launch the thread.
+    auto tempReadThread =
+        std::make_unique<ReadThread>(&mStopReadThread, mStream, tempCommandMQ.get(),
+                                     tempDataMQ.get(), tempStatusMQ.get(), tempElfGroup.get());
+    if (!tempReadThread->init()) {
+        ALOGW("failed to start reader thread: %s", strerror(-status));
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+    status = tempReadThread->run("reader", PRIORITY_URGENT_AUDIO);
+    if (status != OK) {
+        ALOGW("failed to start reader thread: %s", strerror(-status));
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+
+    mCommandMQ = std::move(tempCommandMQ);
+    mDataMQ = std::move(tempDataMQ);
+    mStatusMQ = std::move(tempStatusMQ);
+    mReadThread = tempReadThread.release();
+    mEfGroup = tempElfGroup.release();
+    threadInfo.pid = getpid();
+    threadInfo.tid = mReadThread->getTid();
+    _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
+             threadInfo);
+    return Void();
+}
+
+Return<uint32_t> StreamIn::getInputFramesLost() {
+    return mStream->get_input_frames_lost(mStream);
+}
+
+// static
+Result StreamIn::getCapturePositionImpl(audio_stream_in_t* stream, uint64_t* frames,
+                                        uint64_t* time) {
+    // HAL may have a stub function, always returning ENOSYS, don't
+    // spam the log in this case.
+    static const std::vector<int> ignoredErrors{ENOSYS};
+    Result retval(Result::NOT_SUPPORTED);
+    if (stream->get_capture_position == NULL) return retval;
+    int64_t halFrames, halTime;
+    retval = Stream::analyzeStatus("get_capture_position",
+                                   stream->get_capture_position(stream, &halFrames, &halTime),
+                                   ignoredErrors);
+    if (retval == Result::OK) {
+        *frames = halFrames;
+        *time = halTime;
+    }
+    return retval;
+};
+
+Return<void> StreamIn::getCapturePosition(getCapturePosition_cb _hidl_cb) {
+    uint64_t frames = 0, time = 0;
+    Result retval = getCapturePositionImpl(mStream, &frames, &time);
+    _hidl_cb(retval, frames, time);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.h b/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.h
new file mode 100644
index 0000000..4cfe2e3
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.h
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <atomic>
+#include <memory>
+
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <utils/Thread.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioFormat;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::AudioDrain;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::DeviceAddress;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IStream;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOutCallback;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::ParameterValue;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::audio::AUDIO_HAL_VERSION::TimeSpec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct StreamOut : public IStreamOut {
+    typedef MessageQueue<WriteCommand, kSynchronizedReadWrite> CommandMQ;
+    typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
+    typedef MessageQueue<WriteStatus, kSynchronizedReadWrite> StatusMQ;
+
+    StreamOut(const sp<Device>& device, audio_stream_out_t* stream);
+
+    // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow.
+    Return<uint64_t> getFrameSize() override;
+    Return<uint64_t> getFrameCount() override;
+    Return<uint64_t> getBufferSize() override;
+    Return<uint32_t> getSampleRate() override;
+    Return<void> getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) override;
+    Return<Result> setSampleRate(uint32_t sampleRateHz) override;
+    Return<AudioChannelMask> getChannelMask() override;
+    Return<void> getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) override;
+    Return<Result> setChannelMask(AudioChannelMask mask) override;
+    Return<AudioFormat> getFormat() override;
+    Return<void> getSupportedFormats(getSupportedFormats_cb _hidl_cb) override;
+    Return<Result> setFormat(AudioFormat format) override;
+    Return<void> getAudioProperties(getAudioProperties_cb _hidl_cb) override;
+    Return<Result> addEffect(uint64_t effectId) override;
+    Return<Result> removeEffect(uint64_t effectId) override;
+    Return<Result> standby() override;
+    Return<AudioDevice> getDevice() override;
+    Return<Result> setDevice(const DeviceAddress& address) override;
+    Return<Result> setConnectedState(const DeviceAddress& address, bool connected) override;
+    Return<Result> setHwAvSync(uint32_t hwAvSync) override;
+    Return<void> getParameters(const hidl_vec<hidl_string>& keys,
+                               getParameters_cb _hidl_cb) override;
+    Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
+    Return<void> debugDump(const hidl_handle& fd) override;
+    Return<Result> close() override;
+
+    // Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut follow.
+    Return<uint32_t> getLatency() override;
+    Return<Result> setVolume(float left, float right) override;
+    Return<void> prepareForWriting(uint32_t frameSize, uint32_t framesCount,
+                                   prepareForWriting_cb _hidl_cb) override;
+    Return<void> getRenderPosition(getRenderPosition_cb _hidl_cb) override;
+    Return<void> getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) override;
+    Return<Result> setCallback(const sp<IStreamOutCallback>& callback) override;
+    Return<Result> clearCallback() override;
+    Return<void> supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) override;
+    Return<Result> pause() override;
+    Return<Result> resume() override;
+    Return<bool> supportsDrain() override;
+    Return<Result> drain(AudioDrain type) override;
+    Return<Result> flush() override;
+    Return<void> getPresentationPosition(getPresentationPosition_cb _hidl_cb) override;
+    Return<Result> start() override;
+    Return<Result> stop() override;
+    Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
+    Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
+
+    static Result getPresentationPositionImpl(audio_stream_out_t* stream, uint64_t* frames,
+                                              TimeSpec* timeStamp);
+
+   private:
+    bool mIsClosed;
+    const sp<Device> mDevice;
+    audio_stream_out_t* mStream;
+    const sp<Stream> mStreamCommon;
+    const sp<StreamMmap<audio_stream_out_t>> mStreamMmap;
+    sp<IStreamOutCallback> mCallback;
+    std::unique_ptr<CommandMQ> mCommandMQ;
+    std::unique_ptr<DataMQ> mDataMQ;
+    std::unique_ptr<StatusMQ> mStatusMQ;
+    EventFlag* mEfGroup;
+    std::atomic<bool> mStopWriteThread;
+    sp<Thread> mWriteThread;
+
+    virtual ~StreamOut();
+
+    static int asyncCallback(stream_callback_event_t event, void* param, void* cookie);
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.impl.h
new file mode 100644
index 0000000..bdbeb38
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/StreamOut.impl.h
@@ -0,0 +1,519 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include <memory>
+
+#include <android/log.h>
+#include <hardware/audio.h>
+#include <utils/Trace.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::ThreadInfo;
+using ::android::hardware::audio::all_versions::implementation::isGainNormalized;
+
+namespace {
+
+class WriteThread : public Thread {
+   public:
+    // WriteThread's lifespan never exceeds StreamOut's lifespan.
+    WriteThread(std::atomic<bool>* stop, audio_stream_out_t* stream,
+                StreamOut::CommandMQ* commandMQ, StreamOut::DataMQ* dataMQ,
+                StreamOut::StatusMQ* statusMQ, EventFlag* efGroup)
+        : Thread(false /*canCallJava*/),
+          mStop(stop),
+          mStream(stream),
+          mCommandMQ(commandMQ),
+          mDataMQ(dataMQ),
+          mStatusMQ(statusMQ),
+          mEfGroup(efGroup),
+          mBuffer(nullptr) {}
+    bool init() {
+        mBuffer.reset(new (std::nothrow) uint8_t[mDataMQ->getQuantumCount()]);
+        return mBuffer != nullptr;
+    }
+    virtual ~WriteThread() {}
+
+   private:
+    std::atomic<bool>* mStop;
+    audio_stream_out_t* mStream;
+    StreamOut::CommandMQ* mCommandMQ;
+    StreamOut::DataMQ* mDataMQ;
+    StreamOut::StatusMQ* mStatusMQ;
+    EventFlag* mEfGroup;
+    std::unique_ptr<uint8_t[]> mBuffer;
+    IStreamOut::WriteStatus mStatus;
+
+    bool threadLoop() override;
+
+    void doGetLatency();
+    void doGetPresentationPosition();
+    void doWrite();
+};
+
+void WriteThread::doWrite() {
+    const size_t availToRead = mDataMQ->availableToRead();
+    mStatus.retval = Result::OK;
+    mStatus.reply.written = 0;
+    if (mDataMQ->read(&mBuffer[0], availToRead)) {
+        ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
+        if (writeResult >= 0) {
+            mStatus.reply.written = writeResult;
+        } else {
+            mStatus.retval = Stream::analyzeStatus("write", writeResult);
+        }
+    }
+}
+
+void WriteThread::doGetPresentationPosition() {
+    mStatus.retval =
+        StreamOut::getPresentationPositionImpl(mStream, &mStatus.reply.presentationPosition.frames,
+                                               &mStatus.reply.presentationPosition.timeStamp);
+}
+
+void WriteThread::doGetLatency() {
+    mStatus.retval = Result::OK;
+    mStatus.reply.latencyMs = mStream->get_latency(mStream);
+}
+
+bool WriteThread::threadLoop() {
+    // This implementation doesn't return control back to the Thread until it
+    // decides to stop,
+    // as the Thread uses mutexes, and this can lead to priority inversion.
+    while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+        uint32_t efState = 0;
+        mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState);
+        if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) {
+            continue;  // Nothing to do.
+        }
+        if (!mCommandMQ->read(&mStatus.replyTo)) {
+            continue;  // Nothing to do.
+        }
+        switch (mStatus.replyTo) {
+            case IStreamOut::WriteCommand::WRITE:
+                doWrite();
+                break;
+            case IStreamOut::WriteCommand::GET_PRESENTATION_POSITION:
+                doGetPresentationPosition();
+                break;
+            case IStreamOut::WriteCommand::GET_LATENCY:
+                doGetLatency();
+                break;
+            default:
+                ALOGE("Unknown write thread command code %d", mStatus.replyTo);
+                mStatus.retval = Result::NOT_SUPPORTED;
+                break;
+        }
+        if (!mStatusMQ->write(&mStatus)) {
+            ALOGE("status message queue write failed");
+        }
+        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
+    }
+
+    return false;
+}
+
+}  // namespace
+
+StreamOut::StreamOut(const sp<Device>& device, audio_stream_out_t* stream)
+    : mIsClosed(false),
+      mDevice(device),
+      mStream(stream),
+      mStreamCommon(new Stream(&stream->common)),
+      mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)),
+      mEfGroup(nullptr),
+      mStopWriteThread(false) {}
+
+StreamOut::~StreamOut() {
+    ATRACE_CALL();
+    close();
+    if (mWriteThread.get()) {
+        ATRACE_NAME("mWriteThread->join");
+        status_t status = mWriteThread->join();
+        ALOGE_IF(status, "write thread exit error: %s", strerror(-status));
+    }
+    if (mEfGroup) {
+        status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+        ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status));
+    }
+    mCallback.clear();
+    mDevice->closeOutputStream(mStream);
+    // Closing the output stream in the HAL waits for the callback to finish,
+    // and joins the callback thread. Thus is it guaranteed that the callback
+    // thread will not be accessing our object anymore.
+    mStream = nullptr;
+}
+
+// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStream follow.
+Return<uint64_t> StreamOut::getFrameSize() {
+    return audio_stream_out_frame_size(mStream);
+}
+
+Return<uint64_t> StreamOut::getFrameCount() {
+    return mStreamCommon->getFrameCount();
+}
+
+Return<uint64_t> StreamOut::getBufferSize() {
+    return mStreamCommon->getBufferSize();
+}
+
+Return<uint32_t> StreamOut::getSampleRate() {
+    return mStreamCommon->getSampleRate();
+}
+
+Return<void> StreamOut::getSupportedSampleRates(getSupportedSampleRates_cb _hidl_cb) {
+    return mStreamCommon->getSupportedSampleRates(_hidl_cb);
+}
+
+Return<Result> StreamOut::setSampleRate(uint32_t sampleRateHz) {
+    return mStreamCommon->setSampleRate(sampleRateHz);
+}
+
+Return<AudioChannelMask> StreamOut::getChannelMask() {
+    return mStreamCommon->getChannelMask();
+}
+
+Return<void> StreamOut::getSupportedChannelMasks(getSupportedChannelMasks_cb _hidl_cb) {
+    return mStreamCommon->getSupportedChannelMasks(_hidl_cb);
+}
+
+Return<Result> StreamOut::setChannelMask(AudioChannelMask mask) {
+    return mStreamCommon->setChannelMask(mask);
+}
+
+Return<AudioFormat> StreamOut::getFormat() {
+    return mStreamCommon->getFormat();
+}
+
+Return<void> StreamOut::getSupportedFormats(getSupportedFormats_cb _hidl_cb) {
+    return mStreamCommon->getSupportedFormats(_hidl_cb);
+}
+
+Return<Result> StreamOut::setFormat(AudioFormat format) {
+    return mStreamCommon->setFormat(format);
+}
+
+Return<void> StreamOut::getAudioProperties(getAudioProperties_cb _hidl_cb) {
+    return mStreamCommon->getAudioProperties(_hidl_cb);
+}
+
+Return<Result> StreamOut::addEffect(uint64_t effectId) {
+    return mStreamCommon->addEffect(effectId);
+}
+
+Return<Result> StreamOut::removeEffect(uint64_t effectId) {
+    return mStreamCommon->removeEffect(effectId);
+}
+
+Return<Result> StreamOut::standby() {
+    return mStreamCommon->standby();
+}
+
+Return<AudioDevice> StreamOut::getDevice() {
+    return mStreamCommon->getDevice();
+}
+
+Return<Result> StreamOut::setDevice(const DeviceAddress& address) {
+    return mStreamCommon->setDevice(address);
+}
+
+Return<Result> StreamOut::setConnectedState(const DeviceAddress& address, bool connected) {
+    return mStreamCommon->setConnectedState(address, connected);
+}
+
+Return<Result> StreamOut::setHwAvSync(uint32_t hwAvSync) {
+    return mStreamCommon->setHwAvSync(hwAvSync);
+}
+
+Return<void> StreamOut::getParameters(const hidl_vec<hidl_string>& keys,
+                                      getParameters_cb _hidl_cb) {
+    return mStreamCommon->getParameters(keys, _hidl_cb);
+}
+
+Return<Result> StreamOut::setParameters(const hidl_vec<ParameterValue>& parameters) {
+    return mStreamCommon->setParameters(parameters);
+}
+
+Return<void> StreamOut::debugDump(const hidl_handle& fd) {
+    return mStreamCommon->debugDump(fd);
+}
+
+Return<Result> StreamOut::close() {
+    if (mIsClosed) return Result::INVALID_STATE;
+    mIsClosed = true;
+    if (mWriteThread.get()) {
+        mStopWriteThread.store(true, std::memory_order_release);
+    }
+    if (mEfGroup) {
+        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
+    }
+    return Result::OK;
+}
+
+// Methods from ::android::hardware::audio::AUDIO_HAL_VERSION::IStreamOut follow.
+Return<uint32_t> StreamOut::getLatency() {
+    return mStream->get_latency(mStream);
+}
+
+Return<Result> StreamOut::setVolume(float left, float right) {
+    if (mStream->set_volume == NULL) {
+        return Result::NOT_SUPPORTED;
+    }
+    if (!isGainNormalized(left)) {
+        ALOGW("Can not set a stream output volume {%f, %f} outside [0,1]", left, right);
+        return Result::INVALID_ARGUMENTS;
+    }
+    return Stream::analyzeStatus("set_volume", mStream->set_volume(mStream, left, right));
+}
+
+Return<void> StreamOut::prepareForWriting(uint32_t frameSize, uint32_t framesCount,
+                                          prepareForWriting_cb _hidl_cb) {
+    status_t status;
+    ThreadInfo threadInfo = {0, 0};
+
+    // Wrap the _hidl_cb to return an error
+    auto sendError = [&threadInfo, &_hidl_cb](Result result) {
+        _hidl_cb(result, CommandMQ::Descriptor(), DataMQ::Descriptor(), StatusMQ::Descriptor(),
+                 threadInfo);
+
+    };
+
+    // Create message queues.
+    if (mDataMQ) {
+        ALOGE("the client attempts to call prepareForWriting twice");
+        sendError(Result::INVALID_STATE);
+        return Void();
+    }
+    std::unique_ptr<CommandMQ> tempCommandMQ(new CommandMQ(1));
+
+    // Check frameSize and framesCount
+    if (frameSize == 0 || framesCount == 0) {
+        ALOGE("Null frameSize (%u) or framesCount (%u)", frameSize, framesCount);
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+    if (frameSize > Stream::MAX_BUFFER_SIZE / framesCount) {
+        ALOGE("Buffer too big: %u*%u bytes > MAX_BUFFER_SIZE (%u)", frameSize, framesCount,
+              Stream::MAX_BUFFER_SIZE);
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+    std::unique_ptr<DataMQ> tempDataMQ(new DataMQ(frameSize * framesCount, true /* EventFlag */));
+
+    std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
+    if (!tempCommandMQ->isValid() || !tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
+        ALOGE_IF(!tempCommandMQ->isValid(), "command MQ is invalid");
+        ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
+        ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+    EventFlag* tempRawEfGroup{};
+    status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &tempRawEfGroup);
+    std::unique_ptr<EventFlag, void (*)(EventFlag*)> tempElfGroup(
+        tempRawEfGroup, [](auto* ef) { EventFlag::deleteEventFlag(&ef); });
+    if (status != OK || !tempElfGroup) {
+        ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+
+    // Create and launch the thread.
+    auto tempWriteThread =
+        std::make_unique<WriteThread>(&mStopWriteThread, mStream, tempCommandMQ.get(),
+                                      tempDataMQ.get(), tempStatusMQ.get(), tempElfGroup.get());
+    if (!tempWriteThread->init()) {
+        ALOGW("failed to start writer thread: %s", strerror(-status));
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+    status = tempWriteThread->run("writer", PRIORITY_URGENT_AUDIO);
+    if (status != OK) {
+        ALOGW("failed to start writer thread: %s", strerror(-status));
+        sendError(Result::INVALID_ARGUMENTS);
+        return Void();
+    }
+
+    mCommandMQ = std::move(tempCommandMQ);
+    mDataMQ = std::move(tempDataMQ);
+    mStatusMQ = std::move(tempStatusMQ);
+    mWriteThread = tempWriteThread.release();
+    mEfGroup = tempElfGroup.release();
+    threadInfo.pid = getpid();
+    threadInfo.tid = mWriteThread->getTid();
+    _hidl_cb(Result::OK, *mCommandMQ->getDesc(), *mDataMQ->getDesc(), *mStatusMQ->getDesc(),
+             threadInfo);
+    return Void();
+}
+
+Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
+    uint32_t halDspFrames;
+    Result retval = Stream::analyzeStatus("get_render_position",
+                                          mStream->get_render_position(mStream, &halDspFrames));
+    _hidl_cb(retval, halDspFrames);
+    return Void();
+}
+
+Return<void> StreamOut::getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) {
+    Result retval(Result::NOT_SUPPORTED);
+    int64_t timestampUs = 0;
+    if (mStream->get_next_write_timestamp != NULL) {
+        retval = Stream::analyzeStatus("get_next_write_timestamp",
+                                       mStream->get_next_write_timestamp(mStream, &timestampUs));
+    }
+    _hidl_cb(retval, timestampUs);
+    return Void();
+}
+
+Return<Result> StreamOut::setCallback(const sp<IStreamOutCallback>& callback) {
+    if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
+    // Safe to pass 'this' because it is guaranteed that the callback thread
+    // is joined prior to exit from StreamOut's destructor.
+    int result = mStream->set_callback(mStream, StreamOut::asyncCallback, this);
+    if (result == 0) {
+        mCallback = callback;
+    }
+    return Stream::analyzeStatus("set_callback", result);
+}
+
+Return<Result> StreamOut::clearCallback() {
+    if (mStream->set_callback == NULL) return Result::NOT_SUPPORTED;
+    mCallback.clear();
+    return Result::OK;
+}
+
+// static
+int StreamOut::asyncCallback(stream_callback_event_t event, void*, void* cookie) {
+    // It is guaranteed that the callback thread is joined prior
+    // to exiting from StreamOut's destructor. Must *not* use sp<StreamOut>
+    // here because it can make this code the last owner of StreamOut,
+    // and an attempt to run the destructor on the callback thread
+    // will cause a deadlock in the legacy HAL code.
+    StreamOut* self = reinterpret_cast<StreamOut*>(cookie);
+    // It's correct to hold an sp<> to callback because the reference
+    // in the StreamOut instance can be cleared in the meantime. There is
+    // no difference on which thread to run IStreamOutCallback's destructor.
+    sp<IStreamOutCallback> callback = self->mCallback;
+    if (callback.get() == nullptr) return 0;
+    ALOGV("asyncCallback() event %d", event);
+    switch (event) {
+        case STREAM_CBK_EVENT_WRITE_READY:
+            callback->onWriteReady();
+            break;
+        case STREAM_CBK_EVENT_DRAIN_READY:
+            callback->onDrainReady();
+            break;
+        case STREAM_CBK_EVENT_ERROR:
+            callback->onError();
+            break;
+        default:
+            ALOGW("asyncCallback() unknown event %d", event);
+            break;
+    }
+    return 0;
+}
+
+Return<void> StreamOut::supportsPauseAndResume(supportsPauseAndResume_cb _hidl_cb) {
+    _hidl_cb(mStream->pause != NULL, mStream->resume != NULL);
+    return Void();
+}
+
+Return<Result> StreamOut::pause() {
+    return mStream->pause != NULL ? Stream::analyzeStatus("pause", mStream->pause(mStream))
+                                  : Result::NOT_SUPPORTED;
+}
+
+Return<Result> StreamOut::resume() {
+    return mStream->resume != NULL ? Stream::analyzeStatus("resume", mStream->resume(mStream))
+                                   : Result::NOT_SUPPORTED;
+}
+
+Return<bool> StreamOut::supportsDrain() {
+    return mStream->drain != NULL;
+}
+
+Return<Result> StreamOut::drain(AudioDrain type) {
+    return mStream->drain != NULL
+               ? Stream::analyzeStatus(
+                     "drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type)))
+               : Result::NOT_SUPPORTED;
+}
+
+Return<Result> StreamOut::flush() {
+    return mStream->flush != NULL ? Stream::analyzeStatus("flush", mStream->flush(mStream))
+                                  : Result::NOT_SUPPORTED;
+}
+
+// static
+Result StreamOut::getPresentationPositionImpl(audio_stream_out_t* stream, uint64_t* frames,
+                                              TimeSpec* timeStamp) {
+    // Don't logspam on EINVAL--it's normal for get_presentation_position
+    // to return it sometimes. EAGAIN may be returned by A2DP audio HAL
+    // implementation. ENODATA can also be reported while the writer is
+    // continuously querying it, but the stream has been stopped.
+    static const std::vector<int> ignoredErrors{EINVAL, EAGAIN, ENODATA};
+    Result retval(Result::NOT_SUPPORTED);
+    if (stream->get_presentation_position == NULL) return retval;
+    struct timespec halTimeStamp;
+    retval = Stream::analyzeStatus("get_presentation_position",
+                                   stream->get_presentation_position(stream, frames, &halTimeStamp),
+                                   ignoredErrors);
+    if (retval == Result::OK) {
+        timeStamp->tvSec = halTimeStamp.tv_sec;
+        timeStamp->tvNSec = halTimeStamp.tv_nsec;
+    }
+    return retval;
+}
+
+Return<void> StreamOut::getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
+    uint64_t frames = 0;
+    TimeSpec timeStamp = {0, 0};
+    Result retval = getPresentationPositionImpl(mStream, &frames, &timeStamp);
+    _hidl_cb(retval, frames, timeStamp);
+    return Void();
+}
+
+Return<Result> StreamOut::start() {
+    return mStreamMmap->start();
+}
+
+Return<Result> StreamOut::stop() {
+    return mStreamMmap->stop();
+}
+
+Return<void> StreamOut::createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) {
+    return mStreamMmap->createMmapBuffer(minSizeFrames, audio_stream_out_frame_size(mStream),
+                                         _hidl_cb);
+}
+
+Return<void> StreamOut::getMmapPosition(getMmapPosition_cb _hidl_cb) {
+    return mStreamMmap->getMmapPosition(_hidl_cb);
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Util.h b/audio/core/all-versions/default/include/core/all-versions/default/Util.h
new file mode 100644
index 0000000..39d9dbd
--- /dev/null
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Util.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUDIO_DEVICE_ALL_VERSIONS_UTIL_H
+#define ANDROID_HARDWARE_AUDIO_DEVICE_ALL_VERSIONS_UTIL_H
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace all_versions {
+namespace implementation {
+
+/** @return true if gain is between 0 and 1 included. */
+constexpr bool isGainNormalized(float gain) {
+    return gain >= 0.0 && gain <= 1.0;
+}
+
+}  // namespace implementation
+}  // namespace all_versions
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUDIO_DEVICE_ALL_VERSIONS_UTIL_H
diff --git a/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp b/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp
index 7b9ca30..cadc2f1 100644
--- a/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp
+++ b/audio/effect/2.0/default/AcousticEchoCancelerEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,177 +15,9 @@
  */
 
 #define LOG_TAG "AEC_Effect_HAL"
-#include <system/audio_effects/effect_aec.h>
-#include <android/log.h>
 
 #include "AcousticEchoCancelerEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-AcousticEchoCancelerEffect::AcousticEchoCancelerEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)) {
-}
-
-AcousticEchoCancelerEffect::~AcousticEchoCancelerEffect() {}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> AcousticEchoCancelerEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> AcousticEchoCancelerEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> AcousticEchoCancelerEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> AcousticEchoCancelerEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> AcousticEchoCancelerEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> AcousticEchoCancelerEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> AcousticEchoCancelerEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> AcousticEchoCancelerEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> AcousticEchoCancelerEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> AcousticEchoCancelerEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> AcousticEchoCancelerEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> AcousticEchoCancelerEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> AcousticEchoCancelerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> AcousticEchoCancelerEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> AcousticEchoCancelerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> AcousticEchoCancelerEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> AcousticEchoCancelerEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> AcousticEchoCancelerEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> AcousticEchoCancelerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> AcousticEchoCancelerEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> AcousticEchoCancelerEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> AcousticEchoCancelerEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> AcousticEchoCancelerEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> AcousticEchoCancelerEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> AcousticEchoCancelerEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> AcousticEchoCancelerEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> AcousticEchoCancelerEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> AcousticEchoCancelerEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect follow.
-Return<Result> AcousticEchoCancelerEffect::setEchoDelay(uint32_t echoDelayMs)  {
-    return mEffect->setParam(AEC_PARAM_ECHO_DELAY, echoDelayMs);
-}
-
-Return<void> AcousticEchoCancelerEffect::getEchoDelay(getEchoDelay_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(AEC_PARAM_ECHO_DELAY, _hidl_cb);
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/AcousticEchoCancelerEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/AcousticEchoCancelerEffect.h b/audio/effect/2.0/default/AcousticEchoCancelerEffect.h
index 1ac925d..d36335c 100644
--- a/audio/effect/2.0/default/AcousticEchoCancelerEffect.h
+++ b/audio/effect/2.0/default/AcousticEchoCancelerEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,100 +18,11 @@
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H
 
 #include <android/hardware/audio/effect/2.0/IAcousticEchoCancelerEffect.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct AcousticEchoCancelerEffect : public IAcousticEchoCancelerEffect {
-    explicit AcousticEchoCancelerEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IAcousticEchoCancelerEffect follow.
-    Return<Result> setEchoDelay(uint32_t echoDelayMs)  override;
-    Return<void> getEchoDelay(getEchoDelay_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-
-    virtual ~AcousticEchoCancelerEffect();
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/AcousticEchoCancelerEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ACOUSTICECHOCANCELEREFFECT_H
diff --git a/audio/effect/2.0/default/Android.bp b/audio/effect/2.0/default/Android.bp
index e1072b4..db00988 100644
--- a/audio/effect/2.0/default/Android.bp
+++ b/audio/effect/2.0/default/Android.bp
@@ -31,6 +31,7 @@
         "libhidltransport",
         "liblog",
         "libutils",
+        "android.hardware.audio.common-util",
         "android.hardware.audio.common@2.0",
         "android.hardware.audio.common@2.0-util",
         "android.hardware.audio.effect@2.0",
@@ -38,6 +39,8 @@
     ],
 
     header_libs: [
+        "android.hardware.audio.common.util@all-versions",
+        "android.hardware.audio.effect@all-versions-impl",
         "libaudio_system_headers",
         "libaudioclient_headers",
         "libeffects_headers",
diff --git a/audio/effect/2.0/default/AudioBufferManager.cpp b/audio/effect/2.0/default/AudioBufferManager.cpp
index bba0c4a..39918dd 100644
--- a/audio/effect/2.0/default/AudioBufferManager.cpp
+++ b/audio/effect/2.0/default/AudioBufferManager.cpp
@@ -14,78 +14,8 @@
  * limitations under the License.
  */
 
-#include <atomic>
-
-#include <hidlmemory/mapping.h>
-
 #include "AudioBufferManager.h"
 
-namespace android {
-
-ANDROID_SINGLETON_STATIC_INSTANCE(AudioBufferManager);
-
-bool AudioBufferManager::wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper) {
-    // Check if we have this buffer already
-    std::lock_guard<std::mutex> lock(mLock);
-    ssize_t idx = mBuffers.indexOfKey(buffer.id);
-    if (idx >= 0) {
-        *wrapper = mBuffers[idx].promote();
-        if (*wrapper != nullptr) {
-            (*wrapper)->getHalBuffer()->frameCount = buffer.frameCount;
-            return true;
-        }
-        mBuffers.removeItemsAt(idx);
-    }
-    // Need to create and init a new AudioBufferWrapper.
-    sp<AudioBufferWrapper> tempBuffer(new AudioBufferWrapper(buffer));
-    if (!tempBuffer->init()) return false;
-    *wrapper = tempBuffer;
-    mBuffers.add(buffer.id, *wrapper);
-    return true;
-}
-
-void AudioBufferManager::removeEntry(uint64_t id) {
-    std::lock_guard<std::mutex> lock(mLock);
-    ssize_t idx = mBuffers.indexOfKey(id);
-    if (idx >= 0) mBuffers.removeItemsAt(idx);
-}
-
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-AudioBufferWrapper::AudioBufferWrapper(const AudioBuffer& buffer) :
-        mHidlBuffer(buffer), mHalBuffer{ 0, { nullptr } } {
-}
-
-AudioBufferWrapper::~AudioBufferWrapper() {
-    AudioBufferManager::getInstance().removeEntry(mHidlBuffer.id);
-}
-
-bool AudioBufferWrapper::init() {
-    if (mHalBuffer.raw != nullptr) {
-        ALOGE("An attempt to init AudioBufferWrapper twice");
-        return false;
-    }
-    mHidlMemory = mapMemory(mHidlBuffer.data);
-    if (mHidlMemory == nullptr) {
-        ALOGE("Could not map HIDL memory to IMemory");
-        return false;
-    }
-    mHalBuffer.raw = static_cast<void*>(mHidlMemory->getPointer());
-    if (mHalBuffer.raw == nullptr) {
-        ALOGE("IMemory buffer pointer is null");
-        return false;
-    }
-    mHalBuffer.frameCount = mHidlBuffer.frameCount;
-    return true;
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/AudioBufferManager.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/AudioBufferManager.h b/audio/effect/2.0/default/AudioBufferManager.h
index 6d65995..789fbd1 100644
--- a/audio/effect/2.0/default/AudioBufferManager.h
+++ b/audio/effect/2.0/default/AudioBufferManager.h
@@ -14,69 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef android_hardware_audio_effect_V2_0_AudioBufferManager_H_
-#define android_hardware_audio_effect_V2_0_AudioBufferManager_H_
-
-#include <mutex>
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUDIO_BUFFER_MANAGER_H_
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUDIO_BUFFER_MANAGER_H_
 
 #include <android/hardware/audio/effect/2.0/types.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <system/audio_effect.h>
-#include <utils/RefBase.h>
-#include <utils/KeyedVector.h>
-#include <utils/Singleton.h>
 
-using ::android::hardware::audio::effect::V2_0::AudioBuffer;
-using ::android::hidl::memory::V1_0::IMemory;
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/AudioBufferManager.h>
+#undef AUDIO_HAL_VERSION
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-class AudioBufferWrapper : public RefBase {
-  public:
-    explicit AudioBufferWrapper(const AudioBuffer& buffer);
-    virtual ~AudioBufferWrapper();
-    bool init();
-    audio_buffer_t* getHalBuffer() { return &mHalBuffer; }
-  private:
-    AudioBufferWrapper(const AudioBufferWrapper&) = delete;
-    void operator=(AudioBufferWrapper) = delete;
-
-    AudioBuffer mHidlBuffer;
-    sp<IMemory> mHidlMemory;
-    audio_buffer_t mHalBuffer;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-using ::android::hardware::audio::effect::V2_0::implementation::AudioBufferWrapper;
-
-namespace android {
-
-// This class needs to be in 'android' ns because Singleton macros require that.
-class AudioBufferManager : public Singleton<AudioBufferManager> {
-  public:
-    bool wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper);
-
-  private:
-    friend class hardware::audio::effect::V2_0::implementation::AudioBufferWrapper;
-
-    // Called by AudioBufferWrapper.
-    void removeEntry(uint64_t id);
-
-    std::mutex mLock;
-    KeyedVector<uint64_t, wp<AudioBufferWrapper>> mBuffers;
-};
-
-}  // namespace android
-
-#endif  // android_hardware_audio_effect_V2_0_AudioBufferManager_H_
+#endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUDIO_BUFFER_MANAGER_H_
diff --git a/audio/effect/2.0/default/AutomaticGainControlEffect.cpp b/audio/effect/2.0/default/AutomaticGainControlEffect.cpp
index 62fe5f7..7e00a80 100644
--- a/audio/effect/2.0/default/AutomaticGainControlEffect.cpp
+++ b/audio/effect/2.0/default/AutomaticGainControlEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,223 +15,9 @@
  */
 
 #define LOG_TAG "AGC_Effect_HAL"
-#include <android/log.h>
 
 #include "AutomaticGainControlEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-AutomaticGainControlEffect::AutomaticGainControlEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)) {
-}
-
-AutomaticGainControlEffect::~AutomaticGainControlEffect() {}
-
-void AutomaticGainControlEffect::propertiesFromHal(
-        const t_agc_settings& halProperties,
-        IAutomaticGainControlEffect::AllProperties* properties) {
-    properties->targetLevelMb = halProperties.targetLevel;
-    properties->compGainMb = halProperties.compGain;
-    properties->limiterEnabled = halProperties.limiterEnabled;
-}
-
-void AutomaticGainControlEffect::propertiesToHal(
-        const IAutomaticGainControlEffect::AllProperties& properties,
-        t_agc_settings* halProperties) {
-    halProperties->targetLevel = properties.targetLevelMb;
-    halProperties->compGain = properties.compGainMb;
-    halProperties->limiterEnabled = properties.limiterEnabled;
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> AutomaticGainControlEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> AutomaticGainControlEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> AutomaticGainControlEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> AutomaticGainControlEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> AutomaticGainControlEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> AutomaticGainControlEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> AutomaticGainControlEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> AutomaticGainControlEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> AutomaticGainControlEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> AutomaticGainControlEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> AutomaticGainControlEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> AutomaticGainControlEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> AutomaticGainControlEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> AutomaticGainControlEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> AutomaticGainControlEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> AutomaticGainControlEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> AutomaticGainControlEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> AutomaticGainControlEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> AutomaticGainControlEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> AutomaticGainControlEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> AutomaticGainControlEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> AutomaticGainControlEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> AutomaticGainControlEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> AutomaticGainControlEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> AutomaticGainControlEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> AutomaticGainControlEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> AutomaticGainControlEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> AutomaticGainControlEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect follow.
-Return<Result> AutomaticGainControlEffect::setTargetLevel(int16_t targetLevelMb)  {
-    return mEffect->setParam(AGC_PARAM_TARGET_LEVEL, targetLevelMb);
-}
-
-Return<void> AutomaticGainControlEffect::getTargetLevel(getTargetLevel_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(AGC_PARAM_TARGET_LEVEL, _hidl_cb);
-}
-
-Return<Result> AutomaticGainControlEffect::setCompGain(int16_t compGainMb)  {
-    return mEffect->setParam(AGC_PARAM_COMP_GAIN, compGainMb);
-}
-
-Return<void> AutomaticGainControlEffect::getCompGain(getCompGain_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(AGC_PARAM_COMP_GAIN, _hidl_cb);
-}
-
-Return<Result> AutomaticGainControlEffect::setLimiterEnabled(bool enabled)  {
-    return mEffect->setParam(AGC_PARAM_LIMITER_ENA, enabled);
-}
-
-Return<void> AutomaticGainControlEffect::isLimiterEnabled(isLimiterEnabled_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(AGC_PARAM_LIMITER_ENA, _hidl_cb);
-}
-
-Return<Result> AutomaticGainControlEffect::setAllProperties(const IAutomaticGainControlEffect::AllProperties& properties)  {
-    t_agc_settings halProperties;
-    propertiesToHal(properties, &halProperties);
-    return mEffect->setParam(AGC_PARAM_PROPERTIES, halProperties);
-}
-
-Return<void> AutomaticGainControlEffect::getAllProperties(getAllProperties_cb _hidl_cb)  {
-    t_agc_settings halProperties;
-    Result retval = mEffect->getParam(AGC_PARAM_PROPERTIES, halProperties);
-    AllProperties properties;
-    propertiesFromHal(halProperties, &properties);
-    _hidl_cb(retval, properties);
-    return Void();
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/AutomaticGainControlEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/AutomaticGainControlEffect.h b/audio/effect/2.0/default/AutomaticGainControlEffect.h
index 5e1f279..ef440d2 100644
--- a/audio/effect/2.0/default/AutomaticGainControlEffect.h
+++ b/audio/effect/2.0/default/AutomaticGainControlEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,117 +17,12 @@
 #ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H
 
-#include <system/audio_effects/effect_agc.h>
-
 #include <android/hardware/audio/effect/2.0/IAutomaticGainControlEffect.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct AutomaticGainControlEffect : public IAutomaticGainControlEffect {
-    explicit AutomaticGainControlEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IAutomaticGainControlEffect follow.
-    Return<Result> setTargetLevel(int16_t targetLevelMb)  override;
-    Return<void> getTargetLevel(getTargetLevel_cb _hidl_cb)  override;
-    Return<Result> setCompGain(int16_t compGainMb)  override;
-    Return<void> getCompGain(getCompGain_cb _hidl_cb)  override;
-    Return<Result> setLimiterEnabled(bool enabled)  override;
-    Return<void> isLimiterEnabled(isLimiterEnabled_cb _hidl_cb)  override;
-    Return<Result> setAllProperties(
-            const IAutomaticGainControlEffect::AllProperties& properties)  override;
-    Return<void> getAllProperties(getAllProperties_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-
-    virtual ~AutomaticGainControlEffect();
-
-    void propertiesFromHal(
-            const t_agc_settings& halProperties,
-            IAutomaticGainControlEffect::AllProperties* properties);
-    void propertiesToHal(
-            const IAutomaticGainControlEffect::AllProperties& properties,
-            t_agc_settings* halProperties);
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/AutomaticGainControlEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_AUTOMATICGAINCONTROLEFFECT_H
diff --git a/audio/effect/2.0/default/BassBoostEffect.cpp b/audio/effect/2.0/default/BassBoostEffect.cpp
index 8f35e5f..df9e892 100644
--- a/audio/effect/2.0/default/BassBoostEffect.cpp
+++ b/audio/effect/2.0/default/BassBoostEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,181 +15,9 @@
  */
 
 #define LOG_TAG "BassBoost_HAL"
-#include <system/audio_effects/effect_bassboost.h>
-#include <android/log.h>
 
 #include "BassBoostEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-BassBoostEffect::BassBoostEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)) {
-}
-
-BassBoostEffect::~BassBoostEffect() {}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> BassBoostEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> BassBoostEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> BassBoostEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> BassBoostEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> BassBoostEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> BassBoostEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> BassBoostEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> BassBoostEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> BassBoostEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> BassBoostEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> BassBoostEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> BassBoostEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> BassBoostEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> BassBoostEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> BassBoostEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> BassBoostEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> BassBoostEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> BassBoostEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> BassBoostEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> BassBoostEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> BassBoostEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> BassBoostEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> BassBoostEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> BassBoostEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> BassBoostEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> BassBoostEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> BassBoostEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> BassBoostEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IBassBoostEffect follow.
-Return<void> BassBoostEffect::isStrengthSupported(isStrengthSupported_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH_SUPPORTED, _hidl_cb);
-}
-
-Return<Result> BassBoostEffect::setStrength(uint16_t strength)  {
-    return mEffect->setParam(BASSBOOST_PARAM_STRENGTH, strength);
-}
-
-Return<void> BassBoostEffect::getStrength(getStrength_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH, _hidl_cb);
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/BassBoostEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/BassBoostEffect.h b/audio/effect/2.0/default/BassBoostEffect.h
index 1e5053b..83179e2 100644
--- a/audio/effect/2.0/default/BassBoostEffect.h
+++ b/audio/effect/2.0/default/BassBoostEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,101 +18,13 @@
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H
 
 #include <android/hardware/audio/effect/2.0/IBassBoostEffect.h>
-#include <hidl/Status.h>
 
 #include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::effect::V2_0::IBassBoostEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct BassBoostEffect : public IBassBoostEffect {
-    explicit BassBoostEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IBassBoostEffect follow.
-    Return<void> isStrengthSupported(isStrengthSupported_cb _hidl_cb)  override;
-    Return<Result> setStrength(uint16_t strength)  override;
-    Return<void> getStrength(getStrength_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-
-    virtual ~BassBoostEffect();
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/BassBoostEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_BASSBOOSTEFFECT_H
diff --git a/audio/effect/2.0/default/Conversions.cpp b/audio/effect/2.0/default/Conversions.cpp
index e7d4c46..b59752c 100644
--- a/audio/effect/2.0/default/Conversions.cpp
+++ b/audio/effect/2.0/default/Conversions.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,50 +14,11 @@
  * limitations under the License.
  */
 
-#include <memory.h>
-#include <stdio.h>
-
 #include "Conversions.h"
 #include "HidlUtils.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
+using ::android::hardware::audio::common::V2_0::HidlUtils;
 
-void effectDescriptorFromHal(
-        const effect_descriptor_t& halDescriptor, EffectDescriptor* descriptor) {
-    HidlUtils::uuidFromHal(halDescriptor.type, &descriptor->type);
-    HidlUtils::uuidFromHal(halDescriptor.uuid, &descriptor->uuid);
-    descriptor->flags = EffectFlags(halDescriptor.flags);
-    descriptor->cpuLoad = halDescriptor.cpuLoad;
-    descriptor->memoryUsage = halDescriptor.memoryUsage;
-    memcpy(descriptor->name.data(), halDescriptor.name, descriptor->name.size());
-    memcpy(descriptor->implementor.data(),
-            halDescriptor.implementor, descriptor->implementor.size());
-}
-
-std::string uuidToString(const effect_uuid_t& halUuid) {
-    char str[64];
-    snprintf(str, sizeof(str), "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
-            halUuid.timeLow,
-            halUuid.timeMid,
-            halUuid.timeHiAndVersion,
-            halUuid.clockSeq,
-            halUuid.node[0],
-            halUuid.node[1],
-            halUuid.node[2],
-            halUuid.node[3],
-            halUuid.node[4],
-            halUuid.node[5]);
-    return str;
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/Conversions.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/Conversions.h b/audio/effect/2.0/default/Conversions.h
index 7cef362..94c7f66 100644
--- a/audio/effect/2.0/default/Conversions.h
+++ b/audio/effect/2.0/default/Conversions.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,32 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef android_hardware_audio_effect_V2_0_Conversions_H_
-#define android_hardware_audio_effect_V2_0_Conversions_H_
-
-#include <string>
+#ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_CONVERSIONS_H_
+#define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_CONVERSIONS_H_
 
 #include <android/hardware/audio/effect/2.0/types.h>
-#include <system/audio_effect.h>
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/Conversions.h>
+#undef AUDIO_HAL_VERSION
 
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-
-void effectDescriptorFromHal(
-        const effect_descriptor_t& halDescriptor, EffectDescriptor* descriptor);
-std::string uuidToString(const effect_uuid_t& halUuid);
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // android_hardware_audio_effect_V2_0_Conversions_H_
+#endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_CONVERSIONS_H_
diff --git a/audio/effect/2.0/default/DownmixEffect.cpp b/audio/effect/2.0/default/DownmixEffect.cpp
index 92f15bd..1a51e13 100644
--- a/audio/effect/2.0/default/DownmixEffect.cpp
+++ b/audio/effect/2.0/default/DownmixEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,180 +15,9 @@
  */
 
 #define LOG_TAG "Downmix_HAL"
-#include <system/audio_effects/effect_downmix.h>
-#include <android/log.h>
 
 #include "DownmixEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-DownmixEffect::DownmixEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)) {
-}
-
-DownmixEffect::~DownmixEffect() {}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> DownmixEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> DownmixEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> DownmixEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> DownmixEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> DownmixEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> DownmixEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> DownmixEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> DownmixEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> DownmixEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> DownmixEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> DownmixEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> DownmixEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> DownmixEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> DownmixEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> DownmixEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> DownmixEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> DownmixEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> DownmixEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> DownmixEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> DownmixEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> DownmixEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> DownmixEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> DownmixEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> DownmixEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> DownmixEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> DownmixEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> DownmixEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> DownmixEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IDownmixEffect follow.
-Return<Result> DownmixEffect::setType(IDownmixEffect::Type preset)  {
-    return mEffect->setParam(DOWNMIX_PARAM_TYPE, static_cast<downmix_type_t>(preset));
-}
-
-Return<void> DownmixEffect::getType(getType_cb _hidl_cb)  {
-    downmix_type_t halPreset = DOWNMIX_TYPE_INVALID;
-    Result retval = mEffect->getParam(DOWNMIX_PARAM_TYPE, halPreset);
-    _hidl_cb(retval, Type(halPreset));
-    return Void();
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/DownmixEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/DownmixEffect.h b/audio/effect/2.0/default/DownmixEffect.h
index 125f34d..6dbbb32 100644
--- a/audio/effect/2.0/default/DownmixEffect.h
+++ b/audio/effect/2.0/default/DownmixEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,100 +18,11 @@
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H
 
 #include <android/hardware/audio/effect/2.0/IDownmixEffect.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::effect::V2_0::IDownmixEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct DownmixEffect : public IDownmixEffect {
-    explicit DownmixEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IDownmixEffect follow.
-    Return<Result> setType(IDownmixEffect::Type preset)  override;
-    Return<void> getType(getType_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-
-    virtual ~DownmixEffect();
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/DownmixEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_DOWNMIXEFFECT_H
diff --git a/audio/effect/2.0/default/Effect.cpp b/audio/effect/2.0/default/Effect.cpp
index 184607e..e234e52 100644
--- a/audio/effect/2.0/default/Effect.cpp
+++ b/audio/effect/2.0/default/Effect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,746 +19,10 @@
 #define LOG_TAG "EffectHAL"
 #define ATRACE_TAG ATRACE_TAG_AUDIO
 
-#include <android/log.h>
-#include <media/EffectsFactoryApi.h>
-#include <utils/Trace.h>
-
 #include "Conversions.h"
 #include "Effect.h"
-#include "EffectMap.h"
+#include "common/all-versions/default/EffectMap.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioChannelMask;
-using ::android::hardware::audio::common::V2_0::AudioFormat;
-using ::android::hardware::audio::effect::V2_0::MessageQueueFlagBits;
-
-namespace {
-
-class ProcessThread : public Thread {
-  public:
-    // ProcessThread's lifespan never exceeds Effect's lifespan.
-    ProcessThread(std::atomic<bool>* stop,
-            effect_handle_t effect,
-            std::atomic<audio_buffer_t*>* inBuffer,
-            std::atomic<audio_buffer_t*>* outBuffer,
-            Effect::StatusMQ* statusMQ,
-            EventFlag* efGroup)
-            : Thread(false /*canCallJava*/),
-              mStop(stop),
-              mEffect(effect),
-              mHasProcessReverse((*mEffect)->process_reverse != NULL),
-              mInBuffer(inBuffer),
-              mOutBuffer(outBuffer),
-              mStatusMQ(statusMQ),
-              mEfGroup(efGroup) {
-    }
-    virtual ~ProcessThread() {}
-
-  private:
-    std::atomic<bool>* mStop;
-    effect_handle_t mEffect;
-    bool mHasProcessReverse;
-    std::atomic<audio_buffer_t*>* mInBuffer;
-    std::atomic<audio_buffer_t*>* mOutBuffer;
-    Effect::StatusMQ* mStatusMQ;
-    EventFlag* mEfGroup;
-
-    bool threadLoop() override;
-};
-
-bool ProcessThread::threadLoop() {
-    // This implementation doesn't return control back to the Thread until it decides to stop,
-    // as the Thread uses mutexes, and this can lead to priority inversion.
-    while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
-        uint32_t efState = 0;
-        mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL), &efState);
-        if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL))
-                || (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT))) {
-            continue;  // Nothing to do or time to quit.
-        }
-        Result retval = Result::OK;
-        if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE)
-                && !mHasProcessReverse) {
-            retval = Result::NOT_SUPPORTED;
-        }
-
-        if (retval == Result::OK) {
-            // affects both buffer pointers and their contents.
-            std::atomic_thread_fence(std::memory_order_acquire);
-            int32_t processResult;
-            audio_buffer_t* inBuffer =
-                    std::atomic_load_explicit(mInBuffer, std::memory_order_relaxed);
-            audio_buffer_t* outBuffer =
-                    std::atomic_load_explicit(mOutBuffer, std::memory_order_relaxed);
-            if (inBuffer != nullptr && outBuffer != nullptr) {
-                if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS)) {
-                    processResult = (*mEffect)->process(mEffect, inBuffer, outBuffer);
-                } else {
-                    processResult = (*mEffect)->process_reverse(mEffect, inBuffer, outBuffer);
-                }
-                std::atomic_thread_fence(std::memory_order_release);
-            } else {
-                ALOGE("processing buffers were not set before calling 'process'");
-                processResult = -ENODEV;
-            }
-            switch(processResult) {
-                case 0: retval = Result::OK; break;
-                case -ENODATA: retval = Result::INVALID_STATE; break;
-                case -EINVAL: retval = Result::INVALID_ARGUMENTS; break;
-                default: retval = Result::NOT_INITIALIZED;
-            }
-        }
-        if (!mStatusMQ->write(&retval)) {
-            ALOGW("status message queue write failed");
-        }
-        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING));
-    }
-
-    return false;
-}
-
-}  // namespace
-
-// static
-const char *Effect::sContextResultOfCommand = "returned status";
-const char *Effect::sContextCallToCommand = "error";
-const char *Effect::sContextCallFunction = sContextCallToCommand;
-
-Effect::Effect(effect_handle_t handle)
-        : mIsClosed(false), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {
-}
-
-Effect::~Effect() {
-    ATRACE_CALL();
-    close();
-    if (mProcessThread.get()) {
-        ATRACE_NAME("mProcessThread->join");
-        status_t status = mProcessThread->join();
-        ALOGE_IF(status, "processing thread exit error: %s", strerror(-status));
-    }
-    if (mEfGroup) {
-        status_t status = EventFlag::deleteEventFlag(&mEfGroup);
-        ALOGE_IF(status, "processing MQ event flag deletion error: %s", strerror(-status));
-    }
-    mInBuffer.clear();
-    mOutBuffer.clear();
-    int status = EffectRelease(mHandle);
-    ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
-    EffectMap::getInstance().remove(mHandle);
-    mHandle = 0;
-}
-
-// static
-template<typename T> size_t Effect::alignedSizeIn(size_t s) {
-    return (s + sizeof(T) - 1) / sizeof(T);
-}
-
-// static
-template<typename T> std::unique_ptr<uint8_t[]> Effect::hidlVecToHal(
-        const hidl_vec<T>& vec, uint32_t* halDataSize) {
-    // Due to bugs in HAL, they may attempt to write into the provided
-    // input buffer. The original binder buffer is r/o, thus it is needed
-    // to create a r/w version.
-    *halDataSize = vec.size() * sizeof(T);
-    std::unique_ptr<uint8_t[]> halData(new uint8_t[*halDataSize]);
-    memcpy(&halData[0], &vec[0], *halDataSize);
-    return halData;
-}
-
-// static
-void Effect::effectAuxChannelsConfigFromHal(
-        const channel_config_t& halConfig, EffectAuxChannelsConfig* config) {
-    config->mainChannels = AudioChannelMask(halConfig.main_channels);
-    config->auxChannels = AudioChannelMask(halConfig.aux_channels);
-}
-
-// static
-void Effect::effectAuxChannelsConfigToHal(
-        const EffectAuxChannelsConfig& config, channel_config_t* halConfig) {
-    halConfig->main_channels = static_cast<audio_channel_mask_t>(config.mainChannels);
-    halConfig->aux_channels = static_cast<audio_channel_mask_t>(config.auxChannels);
-}
-
-// static
-void Effect::effectBufferConfigFromHal(
-        const buffer_config_t& halConfig, EffectBufferConfig* config) {
-    config->buffer.id = 0;
-    config->buffer.frameCount = 0;
-    config->samplingRateHz = halConfig.samplingRate;
-    config->channels = AudioChannelMask(halConfig.channels);
-    config->format = AudioFormat(halConfig.format);
-    config->accessMode = EffectBufferAccess(halConfig.accessMode);
-    config->mask = EffectConfigParameters(halConfig.mask);
-}
-
-// static
-void Effect::effectBufferConfigToHal(const EffectBufferConfig& config, buffer_config_t* halConfig) {
-    // Note: setting the buffers directly is considered obsolete. They need to be set
-    // using 'setProcessBuffers'.
-    halConfig->buffer.frameCount = 0;
-    halConfig->buffer.raw = NULL;
-    halConfig->samplingRate = config.samplingRateHz;
-    halConfig->channels = static_cast<uint32_t>(config.channels);
-    // Note: The framework code does not use BP.
-    halConfig->bufferProvider.cookie = NULL;
-    halConfig->bufferProvider.getBuffer = NULL;
-    halConfig->bufferProvider.releaseBuffer = NULL;
-    halConfig->format = static_cast<uint8_t>(config.format);
-    halConfig->accessMode = static_cast<uint8_t>(config.accessMode);
-    halConfig->mask = static_cast<uint8_t>(config.mask);
-}
-
-// static
-void Effect::effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config) {
-    effectBufferConfigFromHal(halConfig.inputCfg, &config->inputCfg);
-    effectBufferConfigFromHal(halConfig.outputCfg, &config->outputCfg);
-}
-
-// static
-void Effect::effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig) {
-    effectBufferConfigToHal(config.inputCfg, &halConfig->inputCfg);
-    effectBufferConfigToHal(config.outputCfg, &halConfig->outputCfg);
-}
-
-// static
-void Effect::effectOffloadParamToHal(
-        const EffectOffloadParameter& offload, effect_offload_param_t* halOffload) {
-    halOffload->isOffload = offload.isOffload;
-    halOffload->ioHandle = offload.ioHandle;
-}
-
-// static
-std::vector<uint8_t> Effect::parameterToHal(
-        uint32_t paramSize,
-        const void* paramData,
-        uint32_t valueSize,
-        const void** valueData) {
-    size_t valueOffsetFromData = alignedSizeIn<uint32_t>(paramSize) * sizeof(uint32_t);
-    size_t halParamBufferSize = sizeof(effect_param_t) + valueOffsetFromData + valueSize;
-    std::vector<uint8_t> halParamBuffer(halParamBufferSize, 0);
-    effect_param_t *halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
-    halParam->psize = paramSize;
-    halParam->vsize = valueSize;
-    memcpy(halParam->data, paramData, paramSize);
-    if (valueData) {
-        if (*valueData) {
-            // Value data is provided.
-            memcpy(halParam->data + valueOffsetFromData, *valueData, valueSize);
-        } else {
-            // The caller needs the pointer to the value data location.
-            *valueData = halParam->data + valueOffsetFromData;
-        }
-    }
-    return halParamBuffer;
-}
-
-Result Effect::analyzeCommandStatus(const char* commandName, const char* context, status_t status) {
-    return analyzeStatus("command", commandName, context, status);
-}
-
-Result Effect::analyzeStatus(
-        const char* funcName,
-        const char* subFuncName,
-        const char* contextDescription,
-        status_t status) {
-    if (status != OK) {
-        ALOGW("Effect %p %s %s %s: %s",
-                mHandle, funcName, subFuncName, contextDescription, strerror(-status));
-    }
-    switch (status) {
-        case OK: return Result::OK;
-        case -EINVAL: return Result::INVALID_ARGUMENTS;
-        case -ENODATA: return Result::INVALID_STATE;
-        case -ENODEV: return Result::NOT_INITIALIZED;
-        case -ENOMEM: return Result::RESULT_TOO_BIG;
-        case -ENOSYS: return Result::NOT_SUPPORTED;
-        default: return Result::INVALID_STATE;
-    }
-}
-
-void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb) {
-    uint32_t halResultSize = sizeof(effect_config_t);
-    effect_config_t halConfig{};
-    status_t status = (*mHandle)->command(
-            mHandle, commandCode, 0, NULL, &halResultSize, &halConfig);
-    EffectConfig config;
-    if (status == OK) {
-        effectConfigFromHal(halConfig, &config);
-    }
-    cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config);
-}
-
-Result Effect::getCurrentConfigImpl(
-        uint32_t featureId, uint32_t configSize, GetCurrentConfigSuccessCallback onSuccess) {
-    uint32_t halCmd = featureId;
-    uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize)];
-    memset(halResult, 0, sizeof(halResult));
-    uint32_t halResultSize = 0;
-    return sendCommandReturningStatusAndData(
-            EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG",
-            sizeof(uint32_t), &halCmd,
-            &halResultSize, halResult,
-            sizeof(uint32_t),
-            [&]{ onSuccess(&halResult[1]); });
-}
-
-Result Effect::getParameterImpl(
-        uint32_t paramSize,
-        const void* paramData,
-        uint32_t requestValueSize,
-        uint32_t replyValueSize,
-        GetParameterSuccessCallback onSuccess) {
-    // As it is unknown what method HAL uses for copying the provided parameter data,
-    // it is safer to make sure that input and output buffers do not overlap.
-    std::vector<uint8_t> halCmdBuffer =
-            parameterToHal(paramSize, paramData, requestValueSize, nullptr);
-    const void *valueData = nullptr;
-    std::vector<uint8_t> halParamBuffer =
-            parameterToHal(paramSize, paramData, replyValueSize, &valueData);
-    uint32_t halParamBufferSize = halParamBuffer.size();
-
-    return sendCommandReturningStatusAndData(
-            EFFECT_CMD_GET_PARAM, "GET_PARAM",
-            halCmdBuffer.size(), &halCmdBuffer[0],
-            &halParamBufferSize, &halParamBuffer[0],
-            sizeof(effect_param_t),
-            [&]{
-                effect_param_t *halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
-                onSuccess(halParam->vsize, valueData);
-            });
-}
-
-Result Effect::getSupportedConfigsImpl(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        GetSupportedConfigsSuccessCallback onSuccess) {
-    uint32_t halCmd[2] = { featureId, maxConfigs };
-    uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * sizeof(configSize);
-    uint8_t halResult[halResultSize];
-    memset(&halResult[0], 0, halResultSize);
-    return sendCommandReturningStatusAndData(
-            EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS",
-            sizeof(halCmd), halCmd,
-            &halResultSize, &halResult[0],
-            2 * sizeof(uint32_t),
-            [&]{
-                uint32_t *halResult32 = reinterpret_cast<uint32_t*>(&halResult[0]);
-                uint32_t supportedConfigs = *(++halResult32); // skip status field
-                if (supportedConfigs > maxConfigs) supportedConfigs = maxConfigs;
-                onSuccess(supportedConfigs, ++halResult32);
-            });
-}
-
-Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
-    status_t status;
-    // Create message queue.
-    if (mStatusMQ) {
-        ALOGE("the client attempts to call prepareForProcessing_cb twice");
-        _hidl_cb(Result::INVALID_STATE, StatusMQ::Descriptor());
-        return Void();
-    }
-    std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1, true /*EventFlag*/));
-    if (!tempStatusMQ->isValid()) {
-        ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
-        _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
-        return Void();
-    }
-    status = EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
-    if (status != OK || !mEfGroup) {
-        ALOGE("failed creating event flag for status MQ: %s", strerror(-status));
-        _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
-        return Void();
-    }
-
-    // Create and launch the thread.
-    mProcessThread = new ProcessThread(
-            &mStopProcessThread,
-            mHandle,
-            &mHalInBufferPtr,
-            &mHalOutBufferPtr,
-            tempStatusMQ.get(),
-            mEfGroup);
-    status = mProcessThread->run("effect", PRIORITY_URGENT_AUDIO);
-    if (status != OK) {
-        ALOGW("failed to start effect processing thread: %s", strerror(-status));
-        _hidl_cb(Result::INVALID_ARGUMENTS, MQDescriptorSync<Result>());
-        return Void();
-    }
-
-    mStatusMQ = std::move(tempStatusMQ);
-    _hidl_cb(Result::OK, *mStatusMQ->getDesc());
-    return Void();
-}
-
-Return<Result> Effect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    AudioBufferManager& manager = AudioBufferManager::getInstance();
-    sp<AudioBufferWrapper> tempInBuffer, tempOutBuffer;
-    if (!manager.wrap(inBuffer, &tempInBuffer)) {
-        ALOGE("Could not map memory of the input buffer");
-        return Result::INVALID_ARGUMENTS;
-    }
-    if (!manager.wrap(outBuffer, &tempOutBuffer)) {
-        ALOGE("Could not map memory of the output buffer");
-        return Result::INVALID_ARGUMENTS;
-    }
-    mInBuffer = tempInBuffer;
-    mOutBuffer = tempOutBuffer;
-    // The processing thread only reads these pointers after waking up by an event flag,
-    // so it's OK to update the pair non-atomically.
-    mHalInBufferPtr.store(mInBuffer->getHalBuffer(), std::memory_order_release);
-    mHalOutBufferPtr.store(mOutBuffer->getHalBuffer(), std::memory_order_release);
-    return Result::OK;
-}
-
-Result Effect::sendCommand(int commandCode, const char* commandName) {
-    return sendCommand(commandCode, commandName, 0, NULL);
-}
-
-Result Effect::sendCommand(
-        int commandCode, const char* commandName, uint32_t size, void* data) {
-    status_t status = (*mHandle)->command(mHandle, commandCode, size, data, 0, NULL);
-    return analyzeCommandStatus(commandName, sContextCallToCommand, status);
-}
-
-Result Effect::sendCommandReturningData(
-        int commandCode, const char* commandName,
-        uint32_t* replySize, void* replyData) {
-    return sendCommandReturningData(commandCode, commandName, 0, NULL, replySize, replyData);
-}
-
-Result Effect::sendCommandReturningData(
-        int commandCode, const char* commandName,
-        uint32_t size, void* data,
-        uint32_t* replySize, void* replyData) {
-    uint32_t expectedReplySize = *replySize;
-    status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
-    if (status == OK && *replySize != expectedReplySize) {
-        status = -ENODATA;
-    }
-    return analyzeCommandStatus(commandName, sContextCallToCommand, status);
-}
-
-Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName) {
-    return sendCommandReturningStatus(commandCode, commandName, 0, NULL);
-}
-
-Result Effect::sendCommandReturningStatus(
-        int commandCode, const char* commandName, uint32_t size, void* data) {
-    uint32_t replyCmdStatus;
-    uint32_t replySize = sizeof(uint32_t);
-    return sendCommandReturningStatusAndData(
-            commandCode, commandName, size, data, &replySize, &replyCmdStatus, replySize, []{});
-}
-
-Result Effect::sendCommandReturningStatusAndData(
-        int commandCode, const char* commandName,
-        uint32_t size, void* data,
-        uint32_t* replySize, void* replyData,
-        uint32_t minReplySize,
-        CommandSuccessCallback onSuccess) {
-    status_t status =
-            (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
-    Result retval;
-    if (status == OK && minReplySize >= sizeof(uint32_t) && *replySize >= minReplySize) {
-        uint32_t commandStatus = *reinterpret_cast<uint32_t*>(replyData);
-        retval = analyzeCommandStatus(commandName, sContextResultOfCommand, commandStatus);
-        if (commandStatus == OK) {
-            onSuccess();
-        }
-    } else {
-        retval = analyzeCommandStatus(commandName, sContextCallToCommand, status);
-    }
-    return retval;
-}
-
-Result Effect::setConfigImpl(
-        int commandCode, const char* commandName,
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    effect_config_t halConfig;
-    effectConfigToHal(config, &halConfig);
-    if (inputBufferProvider != 0) {
-        LOG_FATAL("Using input buffer provider is not supported");
-    }
-    if (outputBufferProvider != 0) {
-        LOG_FATAL("Using output buffer provider is not supported");
-    }
-    return sendCommandReturningStatus(
-            commandCode, commandName, sizeof(effect_config_t), &halConfig);
-}
-
-
-Result Effect::setParameterImpl(
-        uint32_t paramSize, const void* paramData, uint32_t valueSize, const void* valueData) {
-    std::vector<uint8_t> halParamBuffer = parameterToHal(
-            paramSize, paramData, valueSize, &valueData);
-    return sendCommandReturningStatus(
-            EFFECT_CMD_SET_PARAM, "SET_PARAM", halParamBuffer.size(), &halParamBuffer[0]);
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> Effect::init()  {
-    return sendCommandReturningStatus(EFFECT_CMD_INIT, "INIT");
-}
-
-Return<Result> Effect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider)  {
-    return setConfigImpl(
-            EFFECT_CMD_SET_CONFIG, "SET_CONFIG", config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> Effect::reset()  {
-    return sendCommand(EFFECT_CMD_RESET, "RESET");
-}
-
-Return<Result> Effect::enable()  {
-    return sendCommandReturningStatus(EFFECT_CMD_ENABLE, "ENABLE");
-}
-
-Return<Result> Effect::disable()  {
-    return sendCommandReturningStatus(EFFECT_CMD_DISABLE, "DISABLE");
-}
-
-Return<Result> Effect::setDevice(AudioDevice device)  {
-    uint32_t halDevice = static_cast<uint32_t>(device);
-    return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDevice);
-}
-
-Return<void> Effect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  {
-    uint32_t halDataSize;
-    std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
-    uint32_t halResultSize = halDataSize;
-    uint32_t halResult[volumes.size()];
-    Result retval = sendCommandReturningData(
-            EFFECT_CMD_SET_VOLUME, "SET_VOLUME",
-            halDataSize, &halData[0],
-            &halResultSize, halResult);
-    hidl_vec<uint32_t> result;
-    if (retval == Result::OK) {
-        result.setToExternal(&halResult[0], halResultSize);
-    }
-    _hidl_cb(retval, result);
-    return Void();
-}
-
-Return<Result> Effect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  {
-    uint32_t halDataSize;
-    std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
-    return sendCommand(
-            EFFECT_CMD_SET_VOLUME, "SET_VOLUME",
-            halDataSize, &halData[0]);
-}
-
-Return<Result> Effect::setAudioMode(AudioMode mode)  {
-    uint32_t halMode = static_cast<uint32_t>(mode);
-    return sendCommand(
-            EFFECT_CMD_SET_AUDIO_MODE, "SET_AUDIO_MODE", sizeof(uint32_t), &halMode);
-}
-
-Return<Result> Effect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider)  {
-    return setConfigImpl(EFFECT_CMD_SET_CONFIG_REVERSE, "SET_CONFIG_REVERSE",
-            config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> Effect::setInputDevice(AudioDevice device)  {
-    uint32_t halDevice = static_cast<uint32_t>(device);
-    return sendCommand(
-            EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t), &halDevice);
-}
-
-Return<void> Effect::getConfig(getConfig_cb _hidl_cb)  {
-    getConfigImpl(EFFECT_CMD_GET_CONFIG, "GET_CONFIG", _hidl_cb);
-    return Void();
-}
-
-Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb)  {
-    getConfigImpl(EFFECT_CMD_GET_CONFIG_REVERSE, "GET_CONFIG_REVERSE", _hidl_cb);
-    return Void();
-}
-
-Return<void> Effect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  {
-    hidl_vec<EffectAuxChannelsConfig> result;
-    Result retval = getSupportedConfigsImpl(
-            EFFECT_FEATURE_AUX_CHANNELS,
-            maxConfigs,
-            sizeof(channel_config_t),
-            [&] (uint32_t supportedConfigs, void* configsData) {
-                result.resize(supportedConfigs);
-                channel_config_t *config = reinterpret_cast<channel_config_t*>(configsData);
-                for (size_t i = 0; i < result.size(); ++i) {
-                    effectAuxChannelsConfigFromHal(*config++, &result[i]);
-                }
-            });
-    _hidl_cb(retval, result);
-    return Void();
-}
-
-Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  {
-    uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
-    memset(halResult, 0, sizeof(halResult));
-    EffectAuxChannelsConfig result;
-    Result retval = getCurrentConfigImpl(
-            EFFECT_FEATURE_AUX_CHANNELS,
-            sizeof(channel_config_t),
-            [&] (void* configData) {
-                effectAuxChannelsConfigFromHal(
-                        *reinterpret_cast<channel_config_t*>(configData), &result);
-            });
-    _hidl_cb(retval, result);
-    return Void();
-}
-
-Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  {
-    uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
-    halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS;
-    effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1]));
-    return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG,
-            "SET_FEATURE_CONFIG AUX_CHANNELS", sizeof(halCmd), halCmd);
-}
-
-Return<Result> Effect::setAudioSource(AudioSource source)  {
-    uint32_t halSource = static_cast<uint32_t>(source);
-    return sendCommand(
-            EFFECT_CMD_SET_AUDIO_SOURCE, "SET_AUDIO_SOURCE", sizeof(uint32_t), &halSource);
-}
-
-Return<Result> Effect::offload(const EffectOffloadParameter& param)  {
-    effect_offload_param_t halParam;
-    effectOffloadParamToHal(param, &halParam);
-    return sendCommandReturningStatus(
-            EFFECT_CMD_OFFLOAD, "OFFLOAD", sizeof(effect_offload_param_t), &halParam);
-}
-
-Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb)  {
-    effect_descriptor_t halDescriptor;
-    memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
-    status_t status = (*mHandle)->get_descriptor(mHandle, &halDescriptor);
-    EffectDescriptor descriptor;
-    if (status == OK) {
-        effectDescriptorFromHal(halDescriptor, &descriptor);
-    }
-    _hidl_cb(analyzeStatus("get_descriptor", "", sContextCallFunction, status), descriptor);
-    return Void();
-}
-
-Return<void> Effect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb)  {
-    uint32_t halDataSize;
-    std::unique_ptr<uint8_t[]> halData = hidlVecToHal(data, &halDataSize);
-    uint32_t halResultSize = resultMaxSize;
-    std::unique_ptr<uint8_t[]> halResult(new uint8_t[halResultSize]);
-    memset(&halResult[0], 0, halResultSize);
-
-    void* dataPtr = halDataSize > 0 ? &halData[0] : NULL;
-    void* resultPtr = halResultSize > 0 ? &halResult[0] : NULL;
-    status_t status = (*mHandle)->command(
-            mHandle, commandId, halDataSize, dataPtr, &halResultSize, resultPtr);
-    hidl_vec<uint8_t> result;
-    if (status == OK && resultPtr != NULL) {
-        result.setToExternal(&halResult[0], halResultSize);
-    }
-    _hidl_cb(status, result);
-    return Void();
-}
-
-Return<Result> Effect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  {
-    return setParameterImpl(parameter.size(), &parameter[0], value.size(), &value[0]);
-}
-
-Return<void> Effect::getParameter(
-        const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize, getParameter_cb _hidl_cb)  {
-    hidl_vec<uint8_t> value;
-    Result retval = getParameterImpl(
-            parameter.size(),
-            &parameter[0],
-            valueMaxSize,
-            [&] (uint32_t valueSize, const void* valueData) {
-                value.setToExternal(
-                        reinterpret_cast<uint8_t*>(const_cast<void*>(valueData)), valueSize);
-            });
-    _hidl_cb(retval, value);
-    return Void();
-}
-
-Return<void> Effect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb)  {
-    uint32_t configCount = 0;
-    hidl_vec<uint8_t> result;
-    Result retval = getSupportedConfigsImpl(
-            featureId,
-            maxConfigs,
-            configSize,
-            [&] (uint32_t supportedConfigs, void* configsData) {
-                configCount = supportedConfigs;
-                result.resize(configCount * configSize);
-                memcpy(&result[0], configsData, result.size());
-            });
-    _hidl_cb(retval, configCount, result);
-    return Void();
-}
-
-Return<void> Effect::getCurrentConfigForFeature(
-        uint32_t featureId, uint32_t configSize, getCurrentConfigForFeature_cb _hidl_cb)  {
-    hidl_vec<uint8_t> result;
-    Result retval = getCurrentConfigImpl(
-            featureId,
-            configSize,
-            [&] (void* configData) {
-                result.resize(configSize);
-                memcpy(&result[0], configData, result.size());
-            });
-    _hidl_cb(retval, result);
-    return Void();
-}
-
-Return<Result> Effect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData)  {
-    uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size())];
-    memset(halCmd, 0, sizeof(halCmd));
-    halCmd[0] = featureId;
-    memcpy(&halCmd[1], &configData[0], configData.size());
-    return sendCommandReturningStatus(
-            EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG", sizeof(halCmd), halCmd);
-}
-
-Return<Result> Effect::close() {
-    if (mIsClosed) return Result::INVALID_STATE;
-    mIsClosed = true;
-    if (mProcessThread.get()) {
-        mStopProcessThread.store(true, std::memory_order_release);
-    }
-    if (mEfGroup) {
-        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT));
-    }
-    return Result::OK;
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/Effect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/Effect.h b/audio/effect/2.0/default/Effect.h
index 0918cd8..a4d194d 100644
--- a/audio/effect/2.0/default/Effect.h
+++ b/audio/effect/2.0/default/Effect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,259 +17,12 @@
 #ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H
 
-#include <atomic>
-#include <memory>
-#include <vector>
-
 #include <android/hardware/audio/effect/2.0/IEffect.h>
-#include <fmq/EventFlag.h>
-#include <fmq/MessageQueue.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include <utils/Thread.h>
-
-#include <hardware/audio_effect.h>
 
 #include "AudioBufferManager.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::common::V2_0::Uuid;
-using ::android::hardware::audio::effect::V2_0::AudioBuffer;
-using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
-using ::android::hardware::audio::effect::V2_0::EffectConfig;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::EffectFeature;
-using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct Effect : public IEffect {
-    typedef MessageQueue<Result, kSynchronizedReadWrite> StatusMQ;
-    using GetParameterSuccessCallback =
-            std::function<void(uint32_t valueSize, const void* valueData)>;
-
-    explicit Effect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Utility methods for extending interfaces.
-    template<typename T> Return<void> getIntegerParam(
-            uint32_t paramId, std::function<void(Result retval, T paramValue)> cb) {
-        T value;
-        Result retval = getParameterImpl(
-                sizeof(uint32_t), &paramId,
-                sizeof(T),
-                [&] (uint32_t valueSize, const void* valueData) {
-                    if (valueSize > sizeof(T)) valueSize = sizeof(T);
-                    memcpy(&value, valueData, valueSize);
-                });
-        cb(retval, value);
-        return Void();
-    }
-
-    template<typename T> Result getParam(uint32_t paramId, T& paramValue) {
-        return getParameterImpl(
-                sizeof(uint32_t), &paramId,
-                sizeof(T),
-                [&] (uint32_t valueSize, const void* valueData) {
-                    if (valueSize > sizeof(T)) valueSize = sizeof(T);
-                    memcpy(&paramValue, valueData, valueSize);
-                });
-    }
-
-    template<typename T> Result getParam(uint32_t paramId, uint32_t paramArg, T& paramValue) {
-        uint32_t params[2] = { paramId, paramArg };
-        return getParameterImpl(
-                sizeof(params), params,
-                sizeof(T),
-                [&] (uint32_t valueSize, const void* valueData) {
-                    if (valueSize > sizeof(T)) valueSize = sizeof(T);
-                    memcpy(&paramValue, valueData, valueSize);
-                });
-    }
-
-    template<typename T> Result setParam(uint32_t paramId, const T& paramValue) {
-        return setParameterImpl(sizeof(uint32_t), &paramId, sizeof(T), &paramValue);
-    }
-
-    template<typename T> Result setParam(uint32_t paramId, uint32_t paramArg, const T& paramValue) {
-        uint32_t params[2] = { paramId, paramArg };
-        return setParameterImpl(sizeof(params), params, sizeof(T), &paramValue);
-    }
-
-    Result getParameterImpl(
-            uint32_t paramSize,
-            const void* paramData,
-            uint32_t valueSize,
-            GetParameterSuccessCallback onSuccess) {
-        return getParameterImpl(paramSize, paramData, valueSize, valueSize, onSuccess);
-    }
-    Result getParameterImpl(
-            uint32_t paramSize,
-            const void* paramData,
-            uint32_t requestValueSize,
-            uint32_t replyValueSize,
-            GetParameterSuccessCallback onSuccess);
-    Result setParameterImpl(
-            uint32_t paramSize, const void* paramData, uint32_t valueSize, const void* valueData);
-
-  private:
-    friend struct VirtualizerEffect;  // for getParameterImpl
-    friend struct VisualizerEffect;   // to allow executing commands
-
-    using CommandSuccessCallback = std::function<void()>;
-    using GetConfigCallback = std::function<void(Result retval, const EffectConfig& config)>;
-    using GetCurrentConfigSuccessCallback = std::function<void(void* configData)>;
-    using GetSupportedConfigsSuccessCallback =
-            std::function<void(uint32_t supportedConfigs, void* configsData)>;
-
-    static const char *sContextResultOfCommand;
-    static const char *sContextCallToCommand;
-    static const char *sContextCallFunction;
-
-    bool mIsClosed;
-    effect_handle_t mHandle;
-    sp<AudioBufferWrapper> mInBuffer;
-    sp<AudioBufferWrapper> mOutBuffer;
-    std::atomic<audio_buffer_t*> mHalInBufferPtr;
-    std::atomic<audio_buffer_t*> mHalOutBufferPtr;
-    std::unique_ptr<StatusMQ> mStatusMQ;
-    EventFlag* mEfGroup;
-    std::atomic<bool> mStopProcessThread;
-    sp<Thread> mProcessThread;
-
-    virtual ~Effect();
-
-    template<typename T> static size_t alignedSizeIn(size_t s);
-    template<typename T> std::unique_ptr<uint8_t[]> hidlVecToHal(
-            const hidl_vec<T>& vec, uint32_t* halDataSize);
-    static void effectAuxChannelsConfigFromHal(
-            const channel_config_t& halConfig, EffectAuxChannelsConfig* config);
-    static void effectAuxChannelsConfigToHal(
-            const EffectAuxChannelsConfig& config, channel_config_t* halConfig);
-    static void effectBufferConfigFromHal(
-            const buffer_config_t& halConfig, EffectBufferConfig* config);
-    static void effectBufferConfigToHal(
-            const EffectBufferConfig& config, buffer_config_t* halConfig);
-    static void effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config);
-    static void effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig);
-    static void effectOffloadParamToHal(
-            const EffectOffloadParameter& offload, effect_offload_param_t* halOffload);
-    static std::vector<uint8_t> parameterToHal(
-            uint32_t paramSize, const void* paramData, uint32_t valueSize, const void** valueData);
-
-    Result analyzeCommandStatus(
-            const char* commandName, const char* context, status_t status);
-    Result analyzeStatus(
-            const char* funcName,
-            const char* subFuncName,
-            const char* contextDescription,
-            status_t status);
-    void getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb);
-    Result getCurrentConfigImpl(
-            uint32_t featureId, uint32_t configSize, GetCurrentConfigSuccessCallback onSuccess);
-    Result getSupportedConfigsImpl(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            GetSupportedConfigsSuccessCallback onSuccess);
-    Result sendCommand(int commandCode, const char* commandName);
-    Result sendCommand(int commandCode, const char* commandName, uint32_t size, void* data);
-    Result sendCommandReturningData(
-            int commandCode, const char* commandName, uint32_t* replySize, void* replyData);
-    Result sendCommandReturningData(
-            int commandCode, const char* commandName,
-            uint32_t size, void* data,
-            uint32_t* replySize, void* replyData);
-    Result sendCommandReturningStatus(int commandCode, const char* commandName);
-    Result sendCommandReturningStatus(
-            int commandCode, const char* commandName, uint32_t size, void* data);
-    Result sendCommandReturningStatusAndData(
-            int commandCode, const char* commandName,
-            uint32_t size, void* data,
-            uint32_t* replySize, void* replyData,
-            uint32_t minReplySize,
-            CommandSuccessCallback onSuccess);
-    Result setConfigImpl(
-            int commandCode, const char* commandName,
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider);
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/Effect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECT_H
diff --git a/audio/effect/2.0/default/EffectsFactory.cpp b/audio/effect/2.0/default/EffectsFactory.cpp
index 922a922..a48a85f 100644
--- a/audio/effect/2.0/default/EffectsFactory.cpp
+++ b/audio/effect/2.0/default/EffectsFactory.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,191 +15,25 @@
  */
 
 #define LOG_TAG "EffectFactoryHAL"
-#include <media/EffectsFactoryApi.h>
-#include <system/audio_effects/effect_aec.h>
-#include <system/audio_effects/effect_agc.h>
-#include <system/audio_effects/effect_bassboost.h>
-#include <system/audio_effects/effect_downmix.h>
-#include <system/audio_effects/effect_environmentalreverb.h>
-#include <system/audio_effects/effect_equalizer.h>
-#include <system/audio_effects/effect_loudnessenhancer.h>
-#include <system/audio_effects/effect_ns.h>
-#include <system/audio_effects/effect_presetreverb.h>
-#include <system/audio_effects/effect_virtualizer.h>
-#include <system/audio_effects/effect_visualizer.h>
-#include <android/log.h>
-
+#include "EffectsFactory.h"
 #include "AcousticEchoCancelerEffect.h"
 #include "AutomaticGainControlEffect.h"
 #include "BassBoostEffect.h"
 #include "Conversions.h"
 #include "DownmixEffect.h"
-#include "EffectsFactory.h"
-#include "HidlUtils.h"
 #include "Effect.h"
-#include "EffectMap.h"
 #include "EnvironmentalReverbEffect.h"
 #include "EqualizerEffect.h"
+#include "HidlUtils.h"
 #include "LoudnessEnhancerEffect.h"
 #include "NoiseSuppressionEffect.h"
 #include "PresetReverbEffect.h"
 #include "VirtualizerEffect.h"
 #include "VisualizerEffect.h"
+#include "common/all-versions/default/EffectMap.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
+using ::android::hardware::audio::common::V2_0::HidlUtils;
 
-// static
-sp<IEffect> EffectsFactory::dispatchEffectInstanceCreation(
-        const effect_descriptor_t& halDescriptor, effect_handle_t handle) {
-    const effect_uuid_t *halUuid = &halDescriptor.type;
-    if (memcmp(halUuid, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
-        return new AcousticEchoCancelerEffect(handle);
-    } else if (memcmp(halUuid, FX_IID_AGC, sizeof(effect_uuid_t)) == 0) {
-        return new AutomaticGainControlEffect(handle);
-    } else if (memcmp(halUuid, SL_IID_BASSBOOST, sizeof(effect_uuid_t)) == 0) {
-        return new BassBoostEffect(handle);
-    } else if (memcmp(halUuid, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
-        return new DownmixEffect(handle);
-    } else if (memcmp(halUuid, SL_IID_ENVIRONMENTALREVERB, sizeof(effect_uuid_t)) == 0) {
-        return new EnvironmentalReverbEffect(handle);
-    } else if (memcmp(halUuid, SL_IID_EQUALIZER, sizeof(effect_uuid_t)) == 0) {
-        return new EqualizerEffect(handle);
-    } else if (memcmp(halUuid, FX_IID_LOUDNESS_ENHANCER, sizeof(effect_uuid_t)) == 0) {
-        return new LoudnessEnhancerEffect(handle);
-    } else if (memcmp(halUuid, FX_IID_NS, sizeof(effect_uuid_t)) == 0) {
-        return new NoiseSuppressionEffect(handle);
-    } else if (memcmp(halUuid, SL_IID_PRESETREVERB, sizeof(effect_uuid_t)) == 0) {
-        return new PresetReverbEffect(handle);
-    } else if (memcmp(halUuid, SL_IID_VIRTUALIZER, sizeof(effect_uuid_t)) == 0) {
-        return new VirtualizerEffect(handle);
-    } else if (memcmp(halUuid, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) {
-        return new VisualizerEffect(handle);
-    }
-    return new Effect(handle);
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffectsFactory follow.
-Return<void> EffectsFactory::getAllDescriptors(getAllDescriptors_cb _hidl_cb)  {
-    Result retval(Result::OK);
-    hidl_vec<EffectDescriptor> result;
-    uint32_t numEffects;
-    status_t status;
-
-restart:
-    numEffects = 0;
-    status = EffectQueryNumberEffects(&numEffects);
-    if (status != OK) {
-        retval = Result::NOT_INITIALIZED;
-        ALOGE("Error querying number of effects: %s", strerror(-status));
-        goto exit;
-    }
-    result.resize(numEffects);
-    for (uint32_t i = 0; i < numEffects; ++i) {
-        effect_descriptor_t halDescriptor;
-        status = EffectQueryEffect(i, &halDescriptor);
-        if (status == OK) {
-            effectDescriptorFromHal(halDescriptor, &result[i]);
-        } else {
-            ALOGE("Error querying effect at position %d / %d: %s",
-                    i, numEffects, strerror(-status));
-            switch (status) {
-                case -ENOSYS: {
-                    // Effect list has changed.
-                    goto restart;
-                }
-                case -ENOENT: {
-                    // No more effects available.
-                    result.resize(i);
-                }
-                default: {
-                    result.resize(0);
-                    retval = Result::NOT_INITIALIZED;
-                }
-            }
-            break;
-        }
-    }
-
-exit:
-    _hidl_cb(retval, result);
-    return Void();
-}
-
-Return<void> EffectsFactory::getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb)  {
-    effect_uuid_t halUuid;
-    HidlUtils::uuidToHal(uid, &halUuid);
-    effect_descriptor_t halDescriptor;
-    status_t status = EffectGetDescriptor(&halUuid, &halDescriptor);
-    EffectDescriptor descriptor;
-    effectDescriptorFromHal(halDescriptor, &descriptor);
-    Result retval(Result::OK);
-    if (status != OK) {
-        ALOGE("Error querying effect descriptor for %s: %s",
-                uuidToString(halUuid).c_str(), strerror(-status));
-        if (status == -ENOENT) {
-            retval = Result::INVALID_ARGUMENTS;
-        } else {
-            retval = Result::NOT_INITIALIZED;
-        }
-    }
-    _hidl_cb(retval, descriptor);
-    return Void();
-}
-
-Return<void> EffectsFactory::createEffect(
-        const Uuid& uid, int32_t session, int32_t ioHandle, createEffect_cb _hidl_cb)  {
-    effect_uuid_t halUuid;
-    HidlUtils::uuidToHal(uid, &halUuid);
-    effect_handle_t handle;
-    Result retval(Result::OK);
-    status_t status = EffectCreate(&halUuid, session, ioHandle, &handle);
-    sp<IEffect> effect;
-    uint64_t effectId = EffectMap::INVALID_ID;
-    if (status == OK) {
-        effect_descriptor_t halDescriptor;
-        memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
-        status = (*handle)->get_descriptor(handle, &halDescriptor);
-        if (status == OK) {
-            effect = dispatchEffectInstanceCreation(halDescriptor, handle);
-            effectId = EffectMap::getInstance().add(handle);
-        } else {
-            ALOGE("Error querying effect descriptor for %s: %s",
-                    uuidToString(halUuid).c_str(), strerror(-status));
-            EffectRelease(handle);
-        }
-    }
-    if (status != OK) {
-        ALOGE("Error creating effect %s: %s", uuidToString(halUuid).c_str(), strerror(-status));
-        if (status == -ENOENT) {
-            retval = Result::INVALID_ARGUMENTS;
-        } else {
-            retval = Result::NOT_INITIALIZED;
-        }
-    }
-    _hidl_cb(retval, effect, effectId);
-    return Void();
-}
-
-Return<void> EffectsFactory::debugDump(const hidl_handle& fd)  {
-    if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
-        EffectDumpEffects(fd->data[0]);
-    }
-    return Void();
-}
-
-
-IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* /* name */) {
-    return new EffectsFactory();
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/EffectsFactory.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/EffectsFactory.h b/audio/effect/2.0/default/EffectsFactory.h
index 829a534..f1bfbcf 100644
--- a/audio/effect/2.0/default/EffectsFactory.h
+++ b/audio/effect/2.0/default/EffectsFactory.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,47 +20,10 @@
 #include <system/audio_effect.h>
 
 #include <android/hardware/audio/effect/2.0/IEffectsFactory.h>
-#include <hidl/Status.h>
 
 #include <hidl/MQDescriptor.h>
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::Uuid;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::IEffectsFactory;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct EffectsFactory : public IEffectsFactory {
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffectsFactory follow.
-    Return<void> getAllDescriptors(getAllDescriptors_cb _hidl_cb)  override;
-    Return<void> getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb)  override;
-    Return<void> createEffect(
-            const Uuid& uid, int32_t session, int32_t ioHandle, createEffect_cb _hidl_cb)  override;
-    Return<void> debugDump(const hidl_handle& fd)  override;
-
-  private:
-    static sp<IEffect> dispatchEffectInstanceCreation(
-            const effect_descriptor_t& halDescriptor, effect_handle_t handle);
-};
-
-extern "C" IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name);
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/EffectsFactory.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EFFECTSFACTORY_H
diff --git a/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp b/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp
index 86ff368..017dd1f 100644
--- a/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp
+++ b/audio/effect/2.0/default/EnvironmentalReverbEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,298 +19,6 @@
 
 #include "EnvironmentalReverbEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-EnvironmentalReverbEffect::EnvironmentalReverbEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)) {
-}
-
-EnvironmentalReverbEffect::~EnvironmentalReverbEffect() {}
-
-void EnvironmentalReverbEffect::propertiesFromHal(
-        const t_reverb_settings& halProperties,
-        IEnvironmentalReverbEffect::AllProperties* properties) {
-    properties->roomLevel = halProperties.roomLevel;
-    properties->roomHfLevel = halProperties.roomHFLevel;
-    properties->decayTime = halProperties.decayTime;
-    properties->decayHfRatio = halProperties.decayHFRatio;
-    properties->reflectionsLevel = halProperties.reflectionsLevel;
-    properties->reflectionsDelay = halProperties.reflectionsDelay;
-    properties->reverbLevel = halProperties.reverbLevel;
-    properties->reverbDelay = halProperties.reverbDelay;
-    properties->diffusion = halProperties.diffusion;
-    properties->density = halProperties.density;
-}
-
-void EnvironmentalReverbEffect::propertiesToHal(
-        const IEnvironmentalReverbEffect::AllProperties& properties,
-        t_reverb_settings* halProperties) {
-    halProperties->roomLevel = properties.roomLevel;
-    halProperties->roomHFLevel = properties.roomHfLevel;
-    halProperties->decayTime = properties.decayTime;
-    halProperties->decayHFRatio = properties.decayHfRatio;
-    halProperties->reflectionsLevel = properties.reflectionsLevel;
-    halProperties->reflectionsDelay = properties.reflectionsDelay;
-    halProperties->reverbLevel = properties.reverbLevel;
-    halProperties->reverbDelay = properties.reverbDelay;
-    halProperties->diffusion = properties.diffusion;
-    halProperties->density = properties.density;
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> EnvironmentalReverbEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> EnvironmentalReverbEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> EnvironmentalReverbEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> EnvironmentalReverbEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> EnvironmentalReverbEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> EnvironmentalReverbEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> EnvironmentalReverbEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> EnvironmentalReverbEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> EnvironmentalReverbEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> EnvironmentalReverbEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> EnvironmentalReverbEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> EnvironmentalReverbEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> EnvironmentalReverbEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> EnvironmentalReverbEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> EnvironmentalReverbEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> EnvironmentalReverbEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> EnvironmentalReverbEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> EnvironmentalReverbEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> EnvironmentalReverbEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> EnvironmentalReverbEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> EnvironmentalReverbEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> EnvironmentalReverbEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> EnvironmentalReverbEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect follow.
-Return<Result> EnvironmentalReverbEffect::setBypass(bool bypass)  {
-    return mEffect->setParam(REVERB_PARAM_BYPASS, bypass);
-}
-
-Return<void> EnvironmentalReverbEffect::getBypass(getBypass_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(REVERB_PARAM_BYPASS, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setRoomLevel(int16_t roomLevel)  {
-    return mEffect->setParam(REVERB_PARAM_ROOM_LEVEL, roomLevel);
-}
-
-Return<void> EnvironmentalReverbEffect::getRoomLevel(getRoomLevel_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(REVERB_PARAM_ROOM_LEVEL, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setRoomHfLevel(int16_t roomHfLevel)  {
-    return mEffect->setParam(REVERB_PARAM_ROOM_HF_LEVEL, roomHfLevel);
-}
-
-Return<void> EnvironmentalReverbEffect::getRoomHfLevel(getRoomHfLevel_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(REVERB_PARAM_ROOM_HF_LEVEL, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setDecayTime(uint32_t decayTime)  {
-    return mEffect->setParam(REVERB_PARAM_DECAY_TIME, decayTime);
-}
-
-Return<void> EnvironmentalReverbEffect::getDecayTime(getDecayTime_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(REVERB_PARAM_DECAY_TIME, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setDecayHfRatio(int16_t decayHfRatio)  {
-    return mEffect->setParam(REVERB_PARAM_DECAY_HF_RATIO, decayHfRatio);
-}
-
-Return<void> EnvironmentalReverbEffect::getDecayHfRatio(getDecayHfRatio_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(REVERB_PARAM_DECAY_HF_RATIO, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setReflectionsLevel(int16_t reflectionsLevel)  {
-    return mEffect->setParam(REVERB_PARAM_REFLECTIONS_LEVEL, reflectionsLevel);
-}
-
-Return<void> EnvironmentalReverbEffect::getReflectionsLevel(getReflectionsLevel_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(REVERB_PARAM_REFLECTIONS_LEVEL, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setReflectionsDelay(uint32_t reflectionsDelay)  {
-    return mEffect->setParam(REVERB_PARAM_REFLECTIONS_DELAY, reflectionsDelay);
-}
-
-Return<void> EnvironmentalReverbEffect::getReflectionsDelay(getReflectionsDelay_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(REVERB_PARAM_REFLECTIONS_DELAY, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setReverbLevel(int16_t reverbLevel)  {
-    return mEffect->setParam(REVERB_PARAM_REVERB_LEVEL, reverbLevel);
-}
-
-Return<void> EnvironmentalReverbEffect::getReverbLevel(getReverbLevel_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(REVERB_PARAM_REVERB_LEVEL, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setReverbDelay(uint32_t reverbDelay) {
-    return mEffect->setParam(REVERB_PARAM_REVERB_DELAY, reverbDelay);
-}
-
-Return<void> EnvironmentalReverbEffect::getReverbDelay(getReverbDelay_cb _hidl_cb) {
-    return mEffect->getIntegerParam(REVERB_PARAM_REVERB_DELAY, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setDiffusion(int16_t diffusion)  {
-    return mEffect->setParam(REVERB_PARAM_DIFFUSION, diffusion);
-}
-
-Return<void> EnvironmentalReverbEffect::getDiffusion(getDiffusion_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(REVERB_PARAM_DIFFUSION, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setDensity(int16_t density)  {
-    return mEffect->setParam(REVERB_PARAM_DENSITY, density);
-}
-
-Return<void> EnvironmentalReverbEffect::getDensity(getDensity_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(REVERB_PARAM_DENSITY, _hidl_cb);
-}
-
-Return<Result> EnvironmentalReverbEffect::setAllProperties(
-        const IEnvironmentalReverbEffect::AllProperties& properties)  {
-    t_reverb_settings halProperties;
-    propertiesToHal(properties, &halProperties);
-    return mEffect->setParam(REVERB_PARAM_PROPERTIES, halProperties);
-}
-
-Return<void> EnvironmentalReverbEffect::getAllProperties(getAllProperties_cb _hidl_cb)  {
-    t_reverb_settings halProperties;
-    Result retval = mEffect->getParam(REVERB_PARAM_PROPERTIES, halProperties);
-    AllProperties properties;
-    propertiesFromHal(halProperties, &properties);
-    _hidl_cb(retval, properties);
-    return Void();
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/EnvironmentalReverbEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/EnvironmentalReverbEffect.h b/audio/effect/2.0/default/EnvironmentalReverbEffect.h
index 794caac..d93a53f 100644
--- a/audio/effect/2.0/default/EnvironmentalReverbEffect.h
+++ b/audio/effect/2.0/default/EnvironmentalReverbEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,140 +20,11 @@
 #include <system/audio_effects/effect_environmentalreverb.h>
 
 #include <android/hardware/audio/effect/2.0/IEnvironmentalReverbEffect.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::effect::V2_0::AudioBuffer;
-using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
-using ::android::hardware::audio::effect::V2_0::EffectConfig;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
-using ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct EnvironmentalReverbEffect : public IEnvironmentalReverbEffect {
-    explicit EnvironmentalReverbEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEnvironmentalReverbEffect follow.
-    Return<Result> setBypass(bool bypass)  override;
-    Return<void> getBypass(getBypass_cb _hidl_cb)  override;
-    Return<Result> setRoomLevel(int16_t roomLevel)  override;
-    Return<void> getRoomLevel(getRoomLevel_cb _hidl_cb)  override;
-    Return<Result> setRoomHfLevel(int16_t roomHfLevel)  override;
-    Return<void> getRoomHfLevel(getRoomHfLevel_cb _hidl_cb)  override;
-    Return<Result> setDecayTime(uint32_t decayTime)  override;
-    Return<void> getDecayTime(getDecayTime_cb _hidl_cb)  override;
-    Return<Result> setDecayHfRatio(int16_t decayHfRatio)  override;
-    Return<void> getDecayHfRatio(getDecayHfRatio_cb _hidl_cb)  override;
-    Return<Result> setReflectionsLevel(int16_t reflectionsLevel)  override;
-    Return<void> getReflectionsLevel(getReflectionsLevel_cb _hidl_cb)  override;
-    Return<Result> setReflectionsDelay(uint32_t reflectionsDelay)  override;
-    Return<void> getReflectionsDelay(getReflectionsDelay_cb _hidl_cb)  override;
-    Return<Result> setReverbLevel(int16_t reverbLevel)  override;
-    Return<void> getReverbLevel(getReverbLevel_cb _hidl_cb)  override;
-    Return<Result> setReverbDelay(uint32_t reverbDelay)  override;
-    Return<void> getReverbDelay(getReverbDelay_cb _hidl_cb)  override;
-    Return<Result> setDiffusion(int16_t diffusion)  override;
-    Return<void> getDiffusion(getDiffusion_cb _hidl_cb)  override;
-    Return<Result> setDensity(int16_t density)  override;
-    Return<void> getDensity(getDensity_cb _hidl_cb)  override;
-    Return<Result> setAllProperties(
-            const IEnvironmentalReverbEffect::AllProperties& properties)  override;
-    Return<void> getAllProperties(getAllProperties_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-
-    virtual ~EnvironmentalReverbEffect();
-
-    void propertiesFromHal(
-            const t_reverb_settings& halProperties,
-            IEnvironmentalReverbEffect::AllProperties* properties);
-    void propertiesToHal(
-            const IEnvironmentalReverbEffect::AllProperties& properties,
-            t_reverb_settings* halProperties);
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/EnvironmentalReverbEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_ENVIRONMENTALREVERBEFFECT_H
diff --git a/audio/effect/2.0/default/EqualizerEffect.cpp b/audio/effect/2.0/default/EqualizerEffect.cpp
index 808d8eb..d6e056c 100644
--- a/audio/effect/2.0/default/EqualizerEffect.cpp
+++ b/audio/effect/2.0/default/EqualizerEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,298 +14,10 @@
  * limitations under the License.
  */
 
-#include <memory.h>
-
 #define LOG_TAG "Equalizer_HAL"
-#include <android/log.h>
 
 #include "EqualizerEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-EqualizerEffect::EqualizerEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)) {
-}
-
-EqualizerEffect::~EqualizerEffect() {}
-
-void EqualizerEffect::propertiesFromHal(
-        const t_equalizer_settings& halProperties,
-        IEqualizerEffect::AllProperties* properties) {
-    properties->curPreset = halProperties.curPreset;
-    // t_equalizer_settings incorrectly defines bandLevels as uint16_t,
-    // whereas the actual type of values used by effects is int16_t.
-    const int16_t* signedBandLevels =
-            reinterpret_cast<const int16_t*>(&halProperties.bandLevels[0]);
-    properties->bandLevels.setToExternal(
-            const_cast<int16_t*>(signedBandLevels), halProperties.numBands);
-}
-
-std::vector<uint8_t> EqualizerEffect::propertiesToHal(
-        const IEqualizerEffect::AllProperties& properties,
-        t_equalizer_settings** halProperties) {
-    size_t bandsSize = properties.bandLevels.size() * sizeof(uint16_t);
-    std::vector<uint8_t> halBuffer(sizeof(t_equalizer_settings) + bandsSize, 0);
-    *halProperties = reinterpret_cast<t_equalizer_settings*>(&halBuffer[0]);
-    (*halProperties)->curPreset = properties.curPreset;
-    (*halProperties)->numBands = properties.bandLevels.size();
-    memcpy((*halProperties)->bandLevels, &properties.bandLevels[0], bandsSize);
-    return halBuffer;
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> EqualizerEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> EqualizerEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> EqualizerEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> EqualizerEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> EqualizerEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> EqualizerEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> EqualizerEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> EqualizerEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> EqualizerEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> EqualizerEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> EqualizerEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> EqualizerEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> EqualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> EqualizerEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> EqualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> EqualizerEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> EqualizerEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> EqualizerEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> EqualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> EqualizerEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> EqualizerEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> EqualizerEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> EqualizerEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> EqualizerEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> EqualizerEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> EqualizerEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> EqualizerEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> EqualizerEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEqualizerEffect follow.
-Return<void> EqualizerEffect::getNumBands(getNumBands_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(EQ_PARAM_NUM_BANDS, _hidl_cb);
-}
-
-Return<void> EqualizerEffect::getLevelRange(getLevelRange_cb _hidl_cb)  {
-    int16_t halLevels[2] = { 0, 0 };
-    Result retval = mEffect->getParam(EQ_PARAM_LEVEL_RANGE, halLevels);
-    _hidl_cb(retval, halLevels[0], halLevels[1]);
-    return Void();
-}
-
-Return<Result> EqualizerEffect::setBandLevel(uint16_t band, int16_t level)  {
-    return mEffect->setParam(EQ_PARAM_BAND_LEVEL, band, level);
-}
-
-Return<void> EqualizerEffect::getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb)  {
-    int16_t halLevel = 0;
-    Result retval = mEffect->getParam(EQ_PARAM_BAND_LEVEL, band, halLevel);
-    _hidl_cb(retval, halLevel);
-    return Void();
-}
-
-Return<void> EqualizerEffect::getBandCenterFrequency(
-        uint16_t band, getBandCenterFrequency_cb _hidl_cb)  {
-    uint32_t halFreq = 0;
-    Result retval = mEffect->getParam(EQ_PARAM_CENTER_FREQ, band, halFreq);
-    _hidl_cb(retval, halFreq);
-    return Void();
-}
-
-Return<void> EqualizerEffect::getBandFrequencyRange(
-        uint16_t band, getBandFrequencyRange_cb _hidl_cb)  {
-    uint32_t halFreqs[2] = { 0, 0 };
-    Result retval = mEffect->getParam(EQ_PARAM_BAND_FREQ_RANGE, band, halFreqs);
-    _hidl_cb(retval, halFreqs[0], halFreqs[1]);
-    return Void();
-}
-
-Return<void> EqualizerEffect::getBandForFrequency(uint32_t freq, getBandForFrequency_cb _hidl_cb)  {
-    uint16_t halBand = 0;
-    Result retval = mEffect->getParam(EQ_PARAM_GET_BAND, freq, halBand);
-    _hidl_cb(retval, halBand);
-    return Void();
-}
-
-Return<void> EqualizerEffect::getPresetNames(getPresetNames_cb _hidl_cb)  {
-    uint16_t halPresetCount = 0;
-    Result retval = mEffect->getParam(EQ_PARAM_GET_NUM_OF_PRESETS, halPresetCount);
-    hidl_vec<hidl_string> presetNames;
-    if (retval == Result::OK) {
-        presetNames.resize(halPresetCount);
-        for (uint16_t i = 0; i < halPresetCount; ++i) {
-            char halPresetName[EFFECT_STRING_LEN_MAX];
-            retval = mEffect->getParam(EQ_PARAM_GET_PRESET_NAME, i, halPresetName);
-            if (retval == Result::OK) {
-                presetNames[i] = halPresetName;
-            } else {
-                presetNames.resize(i);
-            }
-        }
-    }
-    _hidl_cb(retval, presetNames);
-    return Void();
-}
-
-Return<Result> EqualizerEffect::setCurrentPreset(uint16_t preset)  {
-    return mEffect->setParam(EQ_PARAM_CUR_PRESET, preset);
-}
-
-Return<void> EqualizerEffect::getCurrentPreset(getCurrentPreset_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(EQ_PARAM_CUR_PRESET, _hidl_cb);
-}
-
-Return<Result> EqualizerEffect::setAllProperties(
-        const IEqualizerEffect::AllProperties& properties)  {
-    t_equalizer_settings *halPropertiesPtr = nullptr;
-    std::vector<uint8_t> halBuffer = propertiesToHal(properties, &halPropertiesPtr);
-    uint32_t paramId = EQ_PARAM_PROPERTIES;
-    return mEffect->setParameterImpl(
-            sizeof(paramId), &paramId, halBuffer.size(), halPropertiesPtr);
-}
-
-Return<void> EqualizerEffect::getAllProperties(getAllProperties_cb _hidl_cb)  {
-    uint16_t numBands = 0;
-    Result retval = mEffect->getParam(EQ_PARAM_NUM_BANDS, numBands);
-    AllProperties properties;
-    if (retval != Result::OK) {
-        _hidl_cb(retval, properties);
-        return Void();
-    }
-    size_t valueSize = sizeof(t_equalizer_settings) + sizeof(int16_t) * numBands;
-    uint32_t paramId = EQ_PARAM_PROPERTIES;
-    retval = mEffect->getParameterImpl(
-            sizeof(paramId), &paramId, valueSize,
-            [&] (uint32_t, const void* valueData) {
-                const t_equalizer_settings* halProperties =
-                        reinterpret_cast<const t_equalizer_settings*>(valueData);
-                propertiesFromHal(*halProperties, &properties);
-            });
-    _hidl_cb(retval, properties);
-    return Void();
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/EqualizerEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/EqualizerEffect.h b/audio/effect/2.0/default/EqualizerEffect.h
index 9e8d75b..54cdd50 100644
--- a/audio/effect/2.0/default/EqualizerEffect.h
+++ b/audio/effect/2.0/default/EqualizerEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,133 +17,12 @@
 #ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H
 
-#include <vector>
-
-#include <system/audio_effects/effect_equalizer.h>
-
 #include <android/hardware/audio/effect/2.0/IEqualizerEffect.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::effect::V2_0::AudioBuffer;
-using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
-using ::android::hardware::audio::effect::V2_0::EffectConfig;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
-using ::android::hardware::audio::effect::V2_0::IEqualizerEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct EqualizerEffect : public IEqualizerEffect {
-    explicit EqualizerEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEqualizerEffect follow.
-    Return<void> getNumBands(getNumBands_cb _hidl_cb)  override;
-    Return<void> getLevelRange(getLevelRange_cb _hidl_cb)  override;
-    Return<Result> setBandLevel(uint16_t band, int16_t level)  override;
-    Return<void> getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb)  override;
-    Return<void> getBandCenterFrequency(
-            uint16_t band, getBandCenterFrequency_cb _hidl_cb)  override;
-    Return<void> getBandFrequencyRange(uint16_t band, getBandFrequencyRange_cb _hidl_cb)  override;
-    Return<void> getBandForFrequency(uint32_t freq, getBandForFrequency_cb _hidl_cb)  override;
-    Return<void> getPresetNames(getPresetNames_cb _hidl_cb)  override;
-    Return<Result> setCurrentPreset(uint16_t preset)  override;
-    Return<void> getCurrentPreset(getCurrentPreset_cb _hidl_cb)  override;
-    Return<Result> setAllProperties(const IEqualizerEffect::AllProperties& properties)  override;
-    Return<void> getAllProperties(getAllProperties_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-
-    virtual ~EqualizerEffect();
-
-    void propertiesFromHal(
-            const t_equalizer_settings& halProperties,
-            IEqualizerEffect::AllProperties* properties);
-    std::vector<uint8_t> propertiesToHal(
-            const IEqualizerEffect::AllProperties& properties,
-            t_equalizer_settings** halProperties);
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/EqualizerEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_EQUALIZEREFFECT_H
diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
index fda5eb0..2dca0f4 100644
--- a/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
+++ b/audio/effect/2.0/default/LoudnessEnhancerEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,191 +14,10 @@
  * limitations under the License.
  */
 
-#include <system/audio_effects/effect_loudnessenhancer.h>
-
 #define LOG_TAG "LoudnessEnhancer_HAL"
-#include <system/audio_effects/effect_aec.h>
-#include <android/log.h>
 
 #include "LoudnessEnhancerEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-LoudnessEnhancerEffect::LoudnessEnhancerEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)) {
-}
-
-LoudnessEnhancerEffect::~LoudnessEnhancerEffect() {}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> LoudnessEnhancerEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> LoudnessEnhancerEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> LoudnessEnhancerEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> LoudnessEnhancerEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> LoudnessEnhancerEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> LoudnessEnhancerEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> LoudnessEnhancerEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> LoudnessEnhancerEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> LoudnessEnhancerEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> LoudnessEnhancerEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> LoudnessEnhancerEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> LoudnessEnhancerEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> LoudnessEnhancerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> LoudnessEnhancerEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> LoudnessEnhancerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> LoudnessEnhancerEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> LoudnessEnhancerEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> LoudnessEnhancerEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> LoudnessEnhancerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> LoudnessEnhancerEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> LoudnessEnhancerEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> LoudnessEnhancerEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> LoudnessEnhancerEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> LoudnessEnhancerEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> LoudnessEnhancerEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> LoudnessEnhancerEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> LoudnessEnhancerEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> LoudnessEnhancerEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect follow.
-Return<Result> LoudnessEnhancerEffect::setTargetGain(int32_t targetGainMb)  {
-    return mEffect->setParam(LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB, targetGainMb);
-}
-
-Return<void> LoudnessEnhancerEffect::getTargetGain(getTargetGain_cb _hidl_cb)  {
-    // AOSP Loudness Enhancer expects the size of the request to not include the
-    // size of the parameter.
-    uint32_t paramId = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB;
-    uint32_t targetGainMb = 0;
-    Result retval = mEffect->getParameterImpl(
-            sizeof(paramId), &paramId,
-            0, sizeof(targetGainMb),
-            [&] (uint32_t, const void* valueData) {
-                memcpy(&targetGainMb, valueData, sizeof(targetGainMb));
-            });
-    _hidl_cb(retval, targetGainMb);
-    return Void();
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/LoudnessEnhancerEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/LoudnessEnhancerEffect.h b/audio/effect/2.0/default/LoudnessEnhancerEffect.h
index 039b8d6..992e238 100644
--- a/audio/effect/2.0/default/LoudnessEnhancerEffect.h
+++ b/audio/effect/2.0/default/LoudnessEnhancerEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,110 +18,11 @@
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H
 
 #include <android/hardware/audio/effect/2.0/ILoudnessEnhancerEffect.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::effect::V2_0::AudioBuffer;
-using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
-using ::android::hardware::audio::effect::V2_0::EffectConfig;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
-using ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct LoudnessEnhancerEffect : public ILoudnessEnhancerEffect {
-    explicit LoudnessEnhancerEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::ILoudnessEnhancerEffect follow.
-    Return<Result> setTargetGain(int32_t targetGainMb)  override;
-    Return<void> getTargetGain(getTargetGain_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-
-    virtual ~LoudnessEnhancerEffect();
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/LoudnessEnhancerEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_LOUDNESSENHANCEREFFECT_H
diff --git a/audio/effect/2.0/default/NoiseSuppressionEffect.cpp b/audio/effect/2.0/default/NoiseSuppressionEffect.cpp
index 7c4e06d..089e811 100644
--- a/audio/effect/2.0/default/NoiseSuppressionEffect.cpp
+++ b/audio/effect/2.0/default/NoiseSuppressionEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,220 +15,9 @@
  */
 
 #define LOG_TAG "NS_Effect_HAL"
-#include <android/log.h>
 
 #include "NoiseSuppressionEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-NoiseSuppressionEffect::NoiseSuppressionEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)) {
-}
-
-NoiseSuppressionEffect::~NoiseSuppressionEffect() {}
-
-void NoiseSuppressionEffect::propertiesFromHal(
-        const t_ns_settings& halProperties,
-        INoiseSuppressionEffect::AllProperties* properties) {
-    properties->level = Level(halProperties.level);
-    properties->type = Type(halProperties.type);
-}
-
-void NoiseSuppressionEffect::propertiesToHal(
-        const INoiseSuppressionEffect::AllProperties& properties,
-        t_ns_settings* halProperties) {
-    halProperties->level = static_cast<uint32_t>(properties.level);
-    halProperties->type = static_cast<uint32_t>(properties.type);
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> NoiseSuppressionEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> NoiseSuppressionEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> NoiseSuppressionEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> NoiseSuppressionEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> NoiseSuppressionEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> NoiseSuppressionEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> NoiseSuppressionEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> NoiseSuppressionEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> NoiseSuppressionEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> NoiseSuppressionEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> NoiseSuppressionEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> NoiseSuppressionEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> NoiseSuppressionEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> NoiseSuppressionEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> NoiseSuppressionEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> NoiseSuppressionEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> NoiseSuppressionEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> NoiseSuppressionEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> NoiseSuppressionEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> NoiseSuppressionEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> NoiseSuppressionEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> NoiseSuppressionEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> NoiseSuppressionEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> NoiseSuppressionEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> NoiseSuppressionEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> NoiseSuppressionEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> NoiseSuppressionEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> NoiseSuppressionEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect follow.
-Return<Result> NoiseSuppressionEffect::setSuppressionLevel(INoiseSuppressionEffect::Level level)  {
-    return mEffect->setParam(NS_PARAM_LEVEL, static_cast<int32_t>(level));
-}
-
-Return<void> NoiseSuppressionEffect::getSuppressionLevel(getSuppressionLevel_cb _hidl_cb)  {
-    int32_t halLevel = 0;
-    Result retval = mEffect->getParam(NS_PARAM_LEVEL, halLevel);
-    _hidl_cb(retval, Level(halLevel));
-    return Void();
-}
-
-Return<Result> NoiseSuppressionEffect::setSuppressionType(INoiseSuppressionEffect::Type type)  {
-    return mEffect->setParam(NS_PARAM_TYPE, static_cast<int32_t>(type));
-}
-
-Return<void> NoiseSuppressionEffect::getSuppressionType(getSuppressionType_cb _hidl_cb)  {
-    int32_t halType = 0;
-    Result retval = mEffect->getParam(NS_PARAM_TYPE, halType);
-    _hidl_cb(retval, Type(halType));
-    return Void();
-}
-
-Return<Result> NoiseSuppressionEffect::setAllProperties(
-        const INoiseSuppressionEffect::AllProperties& properties)  {
-    t_ns_settings halProperties;
-    propertiesToHal(properties, &halProperties);
-    return mEffect->setParam(NS_PARAM_PROPERTIES, halProperties);
-}
-
-Return<void> NoiseSuppressionEffect::getAllProperties(getAllProperties_cb _hidl_cb)  {
-    t_ns_settings halProperties;
-    Result retval = mEffect->getParam(NS_PARAM_PROPERTIES, halProperties);
-    AllProperties properties;
-    propertiesFromHal(halProperties, &properties);
-    _hidl_cb(retval, properties);
-    return Void();
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/NoiseSuppressionEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/NoiseSuppressionEffect.h b/audio/effect/2.0/default/NoiseSuppressionEffect.h
index 5491201..0eee4b5 100644
--- a/audio/effect/2.0/default/NoiseSuppressionEffect.h
+++ b/audio/effect/2.0/default/NoiseSuppressionEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,125 +17,12 @@
 #ifndef ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H
 
-#include <system/audio_effects/effect_ns.h>
-
 #include <android/hardware/audio/effect/2.0/INoiseSuppressionEffect.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::effect::V2_0::AudioBuffer;
-using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
-using ::android::hardware::audio::effect::V2_0::EffectConfig;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
-using ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct NoiseSuppressionEffect : public INoiseSuppressionEffect {
-    explicit NoiseSuppressionEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::INoiseSuppressionEffect follow.
-    Return<Result> setSuppressionLevel(INoiseSuppressionEffect::Level level)  override;
-    Return<void> getSuppressionLevel(getSuppressionLevel_cb _hidl_cb)  override;
-    Return<Result> setSuppressionType(INoiseSuppressionEffect::Type type)  override;
-    Return<void> getSuppressionType(getSuppressionType_cb _hidl_cb)  override;
-    Return<Result> setAllProperties(
-            const INoiseSuppressionEffect::AllProperties& properties)  override;
-    Return<void> getAllProperties(getAllProperties_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-
-    virtual ~NoiseSuppressionEffect();
-
-    void propertiesFromHal(
-            const t_ns_settings& halProperties,
-            INoiseSuppressionEffect::AllProperties* properties);
-    void propertiesToHal(
-            const INoiseSuppressionEffect::AllProperties& properties,
-            t_ns_settings* halProperties);
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/NoiseSuppressionEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_NOISESUPPRESSIONEFFECT_H
diff --git a/audio/effect/2.0/default/PresetReverbEffect.cpp b/audio/effect/2.0/default/PresetReverbEffect.cpp
index 5f17791..0648f6a 100644
--- a/audio/effect/2.0/default/PresetReverbEffect.cpp
+++ b/audio/effect/2.0/default/PresetReverbEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,180 +15,9 @@
  */
 
 #define LOG_TAG "PresetReverb_HAL"
-#include <system/audio_effects/effect_presetreverb.h>
-#include <android/log.h>
 
 #include "PresetReverbEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-PresetReverbEffect::PresetReverbEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)) {
-}
-
-PresetReverbEffect::~PresetReverbEffect() {}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> PresetReverbEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> PresetReverbEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> PresetReverbEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> PresetReverbEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> PresetReverbEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> PresetReverbEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> PresetReverbEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> PresetReverbEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> PresetReverbEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> PresetReverbEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> PresetReverbEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> PresetReverbEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> PresetReverbEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> PresetReverbEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> PresetReverbEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> PresetReverbEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> PresetReverbEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> PresetReverbEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> PresetReverbEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> PresetReverbEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> PresetReverbEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> PresetReverbEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> PresetReverbEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> PresetReverbEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> PresetReverbEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> PresetReverbEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> PresetReverbEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> PresetReverbEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IPresetReverbEffect follow.
-Return<Result> PresetReverbEffect::setPreset(IPresetReverbEffect::Preset preset)  {
-    return mEffect->setParam(REVERB_PARAM_PRESET, static_cast<t_reverb_presets>(preset));
-}
-
-Return<void> PresetReverbEffect::getPreset(getPreset_cb _hidl_cb)  {
-    t_reverb_presets halPreset = REVERB_PRESET_NONE;
-    Result retval = mEffect->getParam(REVERB_PARAM_PRESET, halPreset);
-    _hidl_cb(retval, Preset(halPreset));
-    return Void();
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/PresetReverbEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/PresetReverbEffect.h b/audio/effect/2.0/default/PresetReverbEffect.h
index 4eb074a..1ea1626 100644
--- a/audio/effect/2.0/default/PresetReverbEffect.h
+++ b/audio/effect/2.0/default/PresetReverbEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,110 +18,11 @@
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H
 
 #include <android/hardware/audio/effect/2.0/IPresetReverbEffect.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::effect::V2_0::AudioBuffer;
-using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
-using ::android::hardware::audio::effect::V2_0::EffectConfig;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
-using ::android::hardware::audio::effect::V2_0::IPresetReverbEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct PresetReverbEffect : public IPresetReverbEffect {
-    explicit PresetReverbEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IPresetReverbEffect follow.
-    Return<Result> setPreset(IPresetReverbEffect::Preset preset)  override;
-    Return<void> getPreset(getPreset_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-
-    virtual ~PresetReverbEffect();
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/PresetReverbEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_PRESETREVERBEFFECT_H
diff --git a/audio/effect/2.0/default/VirtualizerEffect.cpp b/audio/effect/2.0/default/VirtualizerEffect.cpp
index c1fe52f..63d3eb9 100644
--- a/audio/effect/2.0/default/VirtualizerEffect.cpp
+++ b/audio/effect/2.0/default/VirtualizerEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,235 +14,10 @@
  * limitations under the License.
  */
 
-#include <memory.h>
-
 #define LOG_TAG "Virtualizer_HAL"
-#include <system/audio_effects/effect_virtualizer.h>
-#include <android/log.h>
 
 #include "VirtualizerEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-VirtualizerEffect::VirtualizerEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)) {
-}
-
-VirtualizerEffect::~VirtualizerEffect() {}
-
-void VirtualizerEffect::speakerAnglesFromHal(
-        const int32_t* halAngles, uint32_t channelCount, hidl_vec<SpeakerAngle>& speakerAngles) {
-    speakerAngles.resize(channelCount);
-    for (uint32_t i = 0; i < channelCount; ++i) {
-        speakerAngles[i].mask = AudioChannelMask(*halAngles++);
-        speakerAngles[i].azimuth = *halAngles++;
-        speakerAngles[i].elevation = *halAngles++;
-    }
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> VirtualizerEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> VirtualizerEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> VirtualizerEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> VirtualizerEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> VirtualizerEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> VirtualizerEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> VirtualizerEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> VirtualizerEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> VirtualizerEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> VirtualizerEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> VirtualizerEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> VirtualizerEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> VirtualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> VirtualizerEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> VirtualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> VirtualizerEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> VirtualizerEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> VirtualizerEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> VirtualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> VirtualizerEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> VirtualizerEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> VirtualizerEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> VirtualizerEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> VirtualizerEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> VirtualizerEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> VirtualizerEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> VirtualizerEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> VirtualizerEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IVirtualizerEffect follow.
-Return<bool> VirtualizerEffect::isStrengthSupported()  {
-    bool halSupported = false;
-    mEffect->getParam(VIRTUALIZER_PARAM_STRENGTH_SUPPORTED, halSupported);
-    return halSupported;
-}
-
-Return<Result> VirtualizerEffect::setStrength(uint16_t strength)  {
-    return mEffect->setParam(VIRTUALIZER_PARAM_STRENGTH, strength);
-}
-
-Return<void> VirtualizerEffect::getStrength(getStrength_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(VIRTUALIZER_PARAM_STRENGTH, _hidl_cb);
-}
-
-Return<void> VirtualizerEffect::getVirtualSpeakerAngles(
-        AudioChannelMask mask, AudioDevice device, getVirtualSpeakerAngles_cb _hidl_cb)  {
-    uint32_t channelCount = audio_channel_count_from_out_mask(
-            static_cast<audio_channel_mask_t>(mask));
-    size_t halSpeakerAnglesSize = sizeof(int32_t) * 3 * channelCount;
-    uint32_t halParam[3] = {
-        VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES,
-        static_cast<audio_channel_mask_t>(mask),
-        static_cast<audio_devices_t>(device)
-    };
-    hidl_vec<SpeakerAngle> speakerAngles;
-    Result retval = mEffect->getParameterImpl(
-            sizeof(halParam), halParam,
-            halSpeakerAnglesSize,
-            [&] (uint32_t valueSize, const void* valueData) {
-                if (valueSize > halSpeakerAnglesSize) {
-                    valueSize = halSpeakerAnglesSize;
-                } else if (valueSize < halSpeakerAnglesSize) {
-                    channelCount = valueSize / (sizeof(int32_t) * 3);
-                }
-                speakerAnglesFromHal(
-                        reinterpret_cast<const int32_t*>(valueData), channelCount, speakerAngles);
-            });
-    _hidl_cb(retval, speakerAngles);
-    return Void();
-}
-
-Return<Result> VirtualizerEffect::forceVirtualizationMode(AudioDevice device)  {
-    return mEffect->setParam(
-            VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE, static_cast<audio_devices_t>(device));
-}
-
-Return<void> VirtualizerEffect::getVirtualizationMode(getVirtualizationMode_cb _hidl_cb)  {
-    uint32_t halMode = 0;
-    Result retval = mEffect->getParam(VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE, halMode);
-    _hidl_cb(retval, AudioDevice(halMode));
-    return Void();
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/VirtualizerEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/VirtualizerEffect.h b/audio/effect/2.0/default/VirtualizerEffect.h
index 536775f..04f93c4 100644
--- a/audio/effect/2.0/default/VirtualizerEffect.h
+++ b/audio/effect/2.0/default/VirtualizerEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,121 +18,11 @@
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H
 
 #include <android/hardware/audio/effect/2.0/IVirtualizerEffect.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioChannelMask;
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::effect::V2_0::AudioBuffer;
-using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
-using ::android::hardware::audio::effect::V2_0::EffectConfig;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
-using ::android::hardware::audio::effect::V2_0::IVirtualizerEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct VirtualizerEffect : public IVirtualizerEffect {
-    explicit VirtualizerEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IVirtualizerEffect follow.
-    Return<bool> isStrengthSupported()  override;
-    Return<Result> setStrength(uint16_t strength)  override;
-    Return<void> getStrength(getStrength_cb _hidl_cb)  override;
-    Return<void> getVirtualSpeakerAngles(
-            AudioChannelMask mask,
-            AudioDevice device,
-            getVirtualSpeakerAngles_cb _hidl_cb)  override;
-    Return<Result> forceVirtualizationMode(AudioDevice device)  override;
-    Return<void> getVirtualizationMode(getVirtualizationMode_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-
-    virtual ~VirtualizerEffect();
-
-    void speakerAnglesFromHal(
-            const int32_t* halAngles, uint32_t channelCount, hidl_vec<SpeakerAngle>& speakerAngles);
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/VirtualizerEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VIRTUALIZEREFFECT_H
diff --git a/audio/effect/2.0/default/VisualizerEffect.cpp b/audio/effect/2.0/default/VisualizerEffect.cpp
index 2cd3240..5235524 100644
--- a/audio/effect/2.0/default/VisualizerEffect.cpp
+++ b/audio/effect/2.0/default/VisualizerEffect.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,254 +15,9 @@
  */
 
 #define LOG_TAG "Visualizer_HAL"
-#include <system/audio_effects/effect_visualizer.h>
-#include <android/log.h>
 
 #include "VisualizerEffect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-VisualizerEffect::VisualizerEffect(effect_handle_t handle)
-        : mEffect(new Effect(handle)), mCaptureSize(0), mMeasurementMode(MeasurementMode::NONE) {
-}
-
-VisualizerEffect::~VisualizerEffect() {}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-Return<Result> VisualizerEffect::init() {
-    return mEffect->init();
-}
-
-Return<Result> VisualizerEffect::setConfig(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> VisualizerEffect::reset() {
-    return mEffect->reset();
-}
-
-Return<Result> VisualizerEffect::enable() {
-    return mEffect->enable();
-}
-
-Return<Result> VisualizerEffect::disable() {
-    return mEffect->disable();
-}
-
-Return<Result> VisualizerEffect::setDevice(AudioDevice device) {
-    return mEffect->setDevice(device);
-}
-
-Return<void> VisualizerEffect::setAndGetVolume(
-        const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb) {
-    return mEffect->setAndGetVolume(volumes, _hidl_cb);
-}
-
-Return<Result> VisualizerEffect::volumeChangeNotification(
-        const hidl_vec<uint32_t>& volumes) {
-    return mEffect->volumeChangeNotification(volumes);
-}
-
-Return<Result> VisualizerEffect::setAudioMode(AudioMode mode) {
-    return mEffect->setAudioMode(mode);
-}
-
-Return<Result> VisualizerEffect::setConfigReverse(
-        const EffectConfig& config,
-        const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-        const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
-    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
-}
-
-Return<Result> VisualizerEffect::setInputDevice(AudioDevice device) {
-    return mEffect->setInputDevice(device);
-}
-
-Return<void> VisualizerEffect::getConfig(getConfig_cb _hidl_cb) {
-    return mEffect->getConfig(_hidl_cb);
-}
-
-Return<void> VisualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
-    return mEffect->getConfigReverse(_hidl_cb);
-}
-
-Return<void> VisualizerEffect::getSupportedAuxChannelsConfigs(
-        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
-    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
-}
-
-Return<void> VisualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
-    return mEffect->getAuxChannelsConfig(_hidl_cb);
-}
-
-Return<Result> VisualizerEffect::setAuxChannelsConfig(
-        const EffectAuxChannelsConfig& config) {
-    return mEffect->setAuxChannelsConfig(config);
-}
-
-Return<Result> VisualizerEffect::setAudioSource(AudioSource source) {
-    return mEffect->setAudioSource(source);
-}
-
-Return<Result> VisualizerEffect::offload(const EffectOffloadParameter& param) {
-    return mEffect->offload(param);
-}
-
-Return<void> VisualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
-    return mEffect->getDescriptor(_hidl_cb);
-}
-
-Return<void> VisualizerEffect::prepareForProcessing(
-        prepareForProcessing_cb _hidl_cb) {
-    return mEffect->prepareForProcessing(_hidl_cb);
-}
-
-Return<Result> VisualizerEffect::setProcessBuffers(
-        const AudioBuffer& inBuffer, const AudioBuffer& outBuffer) {
-    return mEffect->setProcessBuffers(inBuffer, outBuffer);
-}
-
-Return<void> VisualizerEffect::command(
-        uint32_t commandId,
-        const hidl_vec<uint8_t>& data,
-        uint32_t resultMaxSize,
-        command_cb _hidl_cb) {
-    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
-}
-
-Return<Result> VisualizerEffect::setParameter(
-        const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value) {
-    return mEffect->setParameter(parameter, value);
-}
-
-Return<void> VisualizerEffect::getParameter(
-        const hidl_vec<uint8_t>& parameter,
-        uint32_t valueMaxSize,
-        getParameter_cb _hidl_cb) {
-    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
-}
-
-Return<void> VisualizerEffect::getSupportedConfigsForFeature(
-        uint32_t featureId,
-        uint32_t maxConfigs,
-        uint32_t configSize,
-        getSupportedConfigsForFeature_cb _hidl_cb) {
-    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
-}
-
-Return<void> VisualizerEffect::getCurrentConfigForFeature(
-        uint32_t featureId,
-        uint32_t configSize,
-        getCurrentConfigForFeature_cb _hidl_cb) {
-    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
-}
-
-Return<Result> VisualizerEffect::setCurrentConfigForFeature(
-        uint32_t featureId, const hidl_vec<uint8_t>& configData) {
-    return mEffect->setCurrentConfigForFeature(featureId, configData);
-}
-
-Return<Result> VisualizerEffect::close() {
-    return mEffect->close();
-}
-
-// Methods from ::android::hardware::audio::effect::V2_0::IVisualizerEffect follow.
-Return<Result> VisualizerEffect::setCaptureSize(uint16_t captureSize)  {
-    Result retval = mEffect->setParam(VISUALIZER_PARAM_CAPTURE_SIZE, captureSize);
-    if (retval == Result::OK) {
-        mCaptureSize = captureSize;
-    }
-    return retval;
-}
-
-Return<void> VisualizerEffect::getCaptureSize(getCaptureSize_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(VISUALIZER_PARAM_CAPTURE_SIZE, _hidl_cb);
-}
-
-Return<Result> VisualizerEffect::setScalingMode(IVisualizerEffect::ScalingMode scalingMode)  {
-    return mEffect->setParam(VISUALIZER_PARAM_SCALING_MODE, static_cast<int32_t>(scalingMode));
-}
-
-Return<void> VisualizerEffect::getScalingMode(getScalingMode_cb _hidl_cb)  {
-    int32_t halMode;
-    Result retval = mEffect->getParam(VISUALIZER_PARAM_SCALING_MODE, halMode);
-    _hidl_cb(retval, ScalingMode(halMode));
-    return Void();
-}
-
-Return<Result> VisualizerEffect::setLatency(uint32_t latencyMs)  {
-    return mEffect->setParam(VISUALIZER_PARAM_LATENCY, latencyMs);
-}
-
-Return<void> VisualizerEffect::getLatency(getLatency_cb _hidl_cb)  {
-    return mEffect->getIntegerParam(VISUALIZER_PARAM_LATENCY, _hidl_cb);
-}
-
-Return<Result> VisualizerEffect::setMeasurementMode(
-        IVisualizerEffect::MeasurementMode measurementMode)  {
-    Result retval = mEffect->setParam(
-            VISUALIZER_PARAM_MEASUREMENT_MODE, static_cast<int32_t>(measurementMode));
-    if (retval == Result::OK) {
-        mMeasurementMode = measurementMode;
-    }
-    return retval;
-}
-
-Return<void> VisualizerEffect::getMeasurementMode(getMeasurementMode_cb _hidl_cb)  {
-    int32_t halMode;
-    Result retval = mEffect->getParam(VISUALIZER_PARAM_MEASUREMENT_MODE, halMode);
-    _hidl_cb(retval, MeasurementMode(halMode));
-    return Void();
-}
-
-Return<void> VisualizerEffect::capture(capture_cb _hidl_cb)  {
-    if (mCaptureSize == 0) {
-        _hidl_cb(Result::NOT_INITIALIZED, hidl_vec<uint8_t>());
-        return Void();
-    }
-    uint32_t halCaptureSize = mCaptureSize;
-    uint8_t halCapture[mCaptureSize];
-    Result retval = mEffect->sendCommandReturningData(
-            VISUALIZER_CMD_CAPTURE, "VISUALIZER_CAPTURE", &halCaptureSize, halCapture);
-    hidl_vec<uint8_t> capture;
-    if (retval == Result::OK) {
-        capture.setToExternal(&halCapture[0], halCaptureSize);
-    }
-    _hidl_cb(retval, capture);
-    return Void();
-}
-
-Return<void> VisualizerEffect::measure(measure_cb _hidl_cb)  {
-    if (mMeasurementMode == MeasurementMode::NONE) {
-        _hidl_cb(Result::NOT_INITIALIZED, Measurement());
-        return Void();
-    }
-    int32_t halMeasurement[MEASUREMENT_COUNT];
-    uint32_t halMeasurementSize = sizeof(halMeasurement);
-    Result retval = mEffect->sendCommandReturningData(
-            VISUALIZER_CMD_MEASURE, "VISUALIZER_MEASURE", &halMeasurementSize, halMeasurement);
-    Measurement measurement = { .mode = MeasurementMode::PEAK_RMS };
-    measurement.value.peakAndRms.peakMb = 0;
-    measurement.value.peakAndRms.rmsMb = 0;
-    if (retval == Result::OK) {
-        measurement.value.peakAndRms.peakMb = halMeasurement[MEASUREMENT_IDX_PEAK];
-        measurement.value.peakAndRms.rmsMb = halMeasurement[MEASUREMENT_IDX_RMS];
-    }
-    _hidl_cb(retval, measurement);
-    return Void();
-}
-
-} // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/VisualizerEffect.impl.h>
+#undef AUDIO_HAL_VERSION
diff --git a/audio/effect/2.0/default/VisualizerEffect.h b/audio/effect/2.0/default/VisualizerEffect.h
index fd40ca8..940f15d 100644
--- a/audio/effect/2.0/default/VisualizerEffect.h
+++ b/audio/effect/2.0/default/VisualizerEffect.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,120 +18,11 @@
 #define ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H
 
 #include <android/hardware/audio/effect/2.0/IVisualizerEffect.h>
-#include <hidl/Status.h>
-
-#include <hidl/MQDescriptor.h>
 
 #include "Effect.h"
 
-namespace android {
-namespace hardware {
-namespace audio {
-namespace effect {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::audio::common::V2_0::AudioMode;
-using ::android::hardware::audio::common::V2_0::AudioSource;
-using ::android::hardware::audio::effect::V2_0::AudioBuffer;
-using ::android::hardware::audio::effect::V2_0::EffectAuxChannelsConfig;
-using ::android::hardware::audio::effect::V2_0::EffectConfig;
-using ::android::hardware::audio::effect::V2_0::EffectDescriptor;
-using ::android::hardware::audio::effect::V2_0::EffectOffloadParameter;
-using ::android::hardware::audio::effect::V2_0::IEffect;
-using ::android::hardware::audio::effect::V2_0::IEffectBufferProviderCallback;
-using ::android::hardware::audio::effect::V2_0::IVisualizerEffect;
-using ::android::hardware::audio::effect::V2_0::Result;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-struct VisualizerEffect : public IVisualizerEffect {
-    explicit VisualizerEffect(effect_handle_t handle);
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IEffect follow.
-    Return<Result> init()  override;
-    Return<Result> setConfig(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> reset()  override;
-    Return<Result> enable()  override;
-    Return<Result> disable()  override;
-    Return<Result> setDevice(AudioDevice device)  override;
-    Return<void> setAndGetVolume(
-            const hidl_vec<uint32_t>& volumes, setAndGetVolume_cb _hidl_cb)  override;
-    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes)  override;
-    Return<Result> setAudioMode(AudioMode mode)  override;
-    Return<Result> setConfigReverse(
-            const EffectConfig& config,
-            const sp<IEffectBufferProviderCallback>& inputBufferProvider,
-            const sp<IEffectBufferProviderCallback>& outputBufferProvider)  override;
-    Return<Result> setInputDevice(AudioDevice device)  override;
-    Return<void> getConfig(getConfig_cb _hidl_cb)  override;
-    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb)  override;
-    Return<void> getSupportedAuxChannelsConfigs(
-            uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb)  override;
-    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb)  override;
-    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config)  override;
-    Return<Result> setAudioSource(AudioSource source)  override;
-    Return<Result> offload(const EffectOffloadParameter& param)  override;
-    Return<void> getDescriptor(getDescriptor_cb _hidl_cb)  override;
-    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb)  override;
-    Return<Result> setProcessBuffers(
-            const AudioBuffer& inBuffer, const AudioBuffer& outBuffer)  override;
-    Return<void> command(
-            uint32_t commandId,
-            const hidl_vec<uint8_t>& data,
-            uint32_t resultMaxSize,
-            command_cb _hidl_cb)  override;
-    Return<Result> setParameter(
-            const hidl_vec<uint8_t>& parameter, const hidl_vec<uint8_t>& value)  override;
-    Return<void> getParameter(
-            const hidl_vec<uint8_t>& parameter,
-            uint32_t valueMaxSize,
-            getParameter_cb _hidl_cb)  override;
-    Return<void> getSupportedConfigsForFeature(
-            uint32_t featureId,
-            uint32_t maxConfigs,
-            uint32_t configSize,
-            getSupportedConfigsForFeature_cb _hidl_cb)  override;
-    Return<void> getCurrentConfigForFeature(
-            uint32_t featureId,
-            uint32_t configSize,
-            getCurrentConfigForFeature_cb _hidl_cb)  override;
-    Return<Result> setCurrentConfigForFeature(
-            uint32_t featureId, const hidl_vec<uint8_t>& configData)  override;
-    Return<Result> close()  override;
-
-    // Methods from ::android::hardware::audio::effect::V2_0::IVisualizerEffect follow.
-    Return<Result> setCaptureSize(uint16_t captureSize)  override;
-    Return<void> getCaptureSize(getCaptureSize_cb _hidl_cb)  override;
-    Return<Result> setScalingMode(IVisualizerEffect::ScalingMode scalingMode)  override;
-    Return<void> getScalingMode(getScalingMode_cb _hidl_cb)  override;
-    Return<Result> setLatency(uint32_t latencyMs)  override;
-    Return<void> getLatency(getLatency_cb _hidl_cb)  override;
-    Return<Result> setMeasurementMode(IVisualizerEffect::MeasurementMode measurementMode)  override;
-    Return<void> getMeasurementMode(getMeasurementMode_cb _hidl_cb)  override;
-    Return<void> capture(capture_cb _hidl_cb)  override;
-    Return<void> measure(measure_cb _hidl_cb)  override;
-
-  private:
-    sp<Effect> mEffect;
-    uint16_t mCaptureSize;
-    MeasurementMode mMeasurementMode;
-
-    virtual ~VisualizerEffect();
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace effect
-}  // namespace audio
-}  // namespace hardware
-}  // namespace android
+#define AUDIO_HAL_VERSION V2_0
+#include <effect/all-versions/default/VisualizerEffect.h>
+#undef AUDIO_HAL_VERSION
 
 #endif  // ANDROID_HARDWARE_AUDIO_EFFECT_V2_0_VISUALIZEREFFECT_H
diff --git a/audio/effect/2.0/vts/functional/Android.bp b/audio/effect/2.0/vts/functional/Android.bp
index 7b421cb..f5a49b3 100644
--- a/audio/effect/2.0/vts/functional/Android.bp
+++ b/audio/effect/2.0/vts/functional/Android.bp
@@ -30,6 +30,7 @@
         "libxml2",
     ],
     shared_libs: [
+        "libeffectsconfig",
         "libicuuc",
     ],
 }
diff --git a/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
index fdc1347..d0bc690 100644
--- a/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
+++ b/audio/effect/2.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
@@ -15,16 +15,18 @@
  */
 
 #include <unistd.h>
+#include <iterator>
+
+#include <media/EffectsConfig.h>
 
 #include "utility/ValidateXml.h"
 
 TEST(CheckConfig, audioEffectsConfigurationValidation) {
     RecordProperty("description",
                    "Verify that the effects configuration file is valid according to the schema");
-    const char* xmlConfigFile = "/vendor/etc/audio_effects.xml";
-    // Not every device uses XML configuration, so only validate
-    // if the XML configuration actually exists.
-    if (access(xmlConfigFile, F_OK) == 0) {
-        ASSERT_VALID_XML(xmlConfigFile, "/data/local/tmp/audio_effects_conf_V2_0.xsd");
-    }
+    using namespace android::effectsConfig;
+
+    std::vector<const char*> locations(std::begin(DEFAULT_LOCATIONS), std::end(DEFAULT_LOCATIONS));
+    EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations,
+                                            "/data/local/tmp/audio_effects_conf_V2_0.xsd");
 }
diff --git a/audio/effect/4.0/Android.bp b/audio/effect/4.0/Android.bp
new file mode 100644
index 0000000..e7676a9
--- /dev/null
+++ b/audio/effect/4.0/Android.bp
@@ -0,0 +1,47 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.audio.effect@4.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IAcousticEchoCancelerEffect.hal",
+        "IAutomaticGainControlEffect.hal",
+        "IBassBoostEffect.hal",
+        "IDownmixEffect.hal",
+        "IEffect.hal",
+        "IEffectBufferProviderCallback.hal",
+        "IEffectsFactory.hal",
+        "IEnvironmentalReverbEffect.hal",
+        "IEqualizerEffect.hal",
+        "ILoudnessEnhancerEffect.hal",
+        "INoiseSuppressionEffect.hal",
+        "IPresetReverbEffect.hal",
+        "IVirtualizerEffect.hal",
+        "IVisualizerEffect.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@4.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "AudioBuffer",
+        "EffectAuxChannelsConfig",
+        "EffectBufferAccess",
+        "EffectBufferConfig",
+        "EffectConfig",
+        "EffectConfigParameters",
+        "EffectDescriptor",
+        "EffectFeature",
+        "EffectFlags",
+        "EffectOffloadParameter",
+        "MessageQueueFlagBits",
+        "Result",
+    ],
+    gen_java: false,
+    gen_java_constants: true,
+}
+
diff --git a/audio/effect/4.0/IAcousticEchoCancelerEffect.hal b/audio/effect/4.0/IAcousticEchoCancelerEffect.hal
new file mode 100644
index 0000000..f495e6f
--- /dev/null
+++ b/audio/effect/4.0/IAcousticEchoCancelerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface IAcousticEchoCancelerEffect extends IEffect {
+    /**
+     * Sets echo delay value in milliseconds.
+     */
+    setEchoDelay(uint32_t echoDelayMs) generates (Result retval);
+
+    /**
+     * Gets echo delay value in milliseconds.
+     */
+    getEchoDelay() generates (Result retval, uint32_t echoDelayMs);
+};
diff --git a/audio/effect/4.0/IAutomaticGainControlEffect.hal b/audio/effect/4.0/IAutomaticGainControlEffect.hal
new file mode 100644
index 0000000..d7fa04c
--- /dev/null
+++ b/audio/effect/4.0/IAutomaticGainControlEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface IAutomaticGainControlEffect extends IEffect {
+    /**
+     * Sets target level in millibels.
+     */
+    setTargetLevel(int16_t targetLevelMb) generates (Result retval);
+
+    /**
+     * Gets target level.
+     */
+    getTargetLevel() generates (Result retval, int16_t targetLevelMb);
+
+    /**
+     * Sets gain in the compression range in millibels.
+     */
+    setCompGain(int16_t compGainMb) generates (Result retval);
+
+    /**
+     * Gets gain in the compression range.
+     */
+    getCompGain() generates (Result retval, int16_t compGainMb);
+
+    /**
+     * Enables or disables limiter.
+     */
+    setLimiterEnabled(bool enabled) generates (Result retval);
+
+    /**
+     * Returns whether limiter is enabled.
+     */
+    isLimiterEnabled() generates (Result retval, bool enabled);
+
+    struct AllProperties {
+        int16_t targetLevelMb;
+        int16_t compGainMb;
+        bool limiterEnabled;
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/4.0/IBassBoostEffect.hal b/audio/effect/4.0/IBassBoostEffect.hal
new file mode 100644
index 0000000..bd302f6
--- /dev/null
+++ b/audio/effect/4.0/IBassBoostEffect.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface IBassBoostEffect extends IEffect {
+    /**
+     * Returns whether setting bass boost strength is supported.
+     */
+    isStrengthSupported() generates (Result retval, bool strengthSupported);
+
+    enum StrengthRange : uint16_t {
+        MIN = 0,
+        MAX = 1000
+    };
+
+    /**
+     * Sets bass boost strength.
+     *
+     * @param strength strength of the effect. The valid range for strength
+     *                 strength is [0, 1000], where 0 per mille designates the
+     *                 mildest effect and 1000 per mille designates the
+     *                 strongest.
+     * @return retval operation completion status.
+     */
+    setStrength(uint16_t strength) generates (Result retval);
+
+    /**
+     * Gets virtualization strength.
+     */
+    getStrength() generates (Result retval, uint16_t strength);
+};
diff --git a/audio/effect/4.0/IDownmixEffect.hal b/audio/effect/4.0/IDownmixEffect.hal
new file mode 100644
index 0000000..3ce3a79
--- /dev/null
+++ b/audio/effect/4.0/IDownmixEffect.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface IDownmixEffect extends IEffect {
+    enum Type : int32_t {
+        STRIP, // throw away the extra channels
+        FOLD   // mix the extra channels with FL/FR
+    };
+
+    /**
+     * Sets the current downmix preset.
+     */
+    setType(Type preset) generates (Result retval);
+
+    /**
+     * Gets the current downmix preset.
+     */
+    getType() generates (Result retval, Type preset);
+};
diff --git a/audio/effect/4.0/IEffect.hal b/audio/effect/4.0/IEffect.hal
new file mode 100644
index 0000000..d1d9496
--- /dev/null
+++ b/audio/effect/4.0/IEffect.hal
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffectBufferProviderCallback;
+
+interface IEffect {
+    /**
+     * Initialize effect engine--all configurations return to default.
+     *
+     * @return retval operation completion status.
+     */
+    @entry
+    init() generates (Result retval);
+
+    /**
+     * Apply new audio parameters configurations for input and output buffers.
+     * The provider callbacks may be empty, but in this case the buffer
+     * must be provided in the EffectConfig structure.
+     *
+     * @param config configuration descriptor.
+     * @param inputBufferProvider optional buffer provider reference.
+     * @param outputBufferProvider optional buffer provider reference.
+     * @return retval operation completion status.
+     */
+    setConfig(EffectConfig config,
+            IEffectBufferProviderCallback inputBufferProvider,
+            IEffectBufferProviderCallback outputBufferProvider)
+            generates (Result retval);
+
+    /**
+     * Reset the effect engine. Keep configuration but resets state and buffer
+     * content.
+     *
+     * @return retval operation completion status.
+     */
+    reset() generates (Result retval);
+
+    /**
+     * Enable processing.
+     *
+     * @return retval operation completion status.
+     */
+    @callflow(next={"prepareForProcessing"})
+    enable() generates (Result retval);
+
+    /**
+     * Disable processing.
+     *
+     * @return retval operation completion status.
+     */
+    @callflow(next={"close"})
+    disable() generates (Result retval);
+
+    /**
+     * Set the rendering device the audio output path is connected to.  The
+     * effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its
+     * descriptor to receive this command when the device changes.
+     *
+     * Note: this method is only supported for effects inserted into
+     *       the output chain.
+     *
+     * @param device output device specification.
+     * @return retval operation completion status.
+     */
+    setDevice(bitfield<AudioDevice> device) generates (Result retval);
+
+    /**
+     * Set and get volume. Used by audio framework to delegate volume control to
+     * effect engine. The effect implementation must set EFFECT_FLAG_VOLUME_CTRL
+     * flag in its descriptor to receive this command. The effect engine must
+     * return the volume that should be applied before the effect is
+     * processed. The overall volume (the volume actually applied by the effect
+     * engine multiplied by the returned value) should match the value indicated
+     * in the command.
+     *
+     * @param volumes vector containing volume for each channel defined in
+     *                EffectConfig for output buffer expressed in 8.24 fixed
+     *                point format.
+     * @return result updated volume values.
+     * @return retval operation completion status.
+     */
+    setAndGetVolume(vec<uint32_t> volumes)
+            generates (Result retval, vec<uint32_t> result);
+
+    /**
+     * Notify the effect of the volume change. The effect implementation must
+     * set EFFECT_FLAG_VOLUME_IND flag in its descriptor to receive this
+     * command.
+     *
+     * @param volumes vector containing volume for each channel defined in
+     *                EffectConfig for output buffer expressed in 8.24 fixed
+     *                point format.
+     * @return retval operation completion status.
+     */
+    volumeChangeNotification(vec<uint32_t> volumes)
+            generates (Result retval);
+
+    /**
+     * Set the audio mode. The effect implementation must set
+     * EFFECT_FLAG_AUDIO_MODE_IND flag in its descriptor to receive this command
+     * when the audio mode changes.
+     *
+     * @param mode desired audio mode.
+     * @return retval operation completion status.
+     */
+    setAudioMode(AudioMode mode) generates (Result retval);
+
+    /**
+     * Apply new audio parameters configurations for input and output buffers of
+     * reverse stream.  An example of reverse stream is the echo reference
+     * supplied to an Acoustic Echo Canceler.
+     *
+     * @param config configuration descriptor.
+     * @param inputBufferProvider optional buffer provider reference.
+     * @param outputBufferProvider optional buffer provider reference.
+     * @return retval operation completion status.
+     */
+    setConfigReverse(EffectConfig config,
+            IEffectBufferProviderCallback inputBufferProvider,
+            IEffectBufferProviderCallback outputBufferProvider)
+            generates (Result retval);
+
+    /**
+     * Set the capture device the audio input path is connected to. The effect
+     * implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to
+     * receive this command when the device changes.
+     *
+     * Note: this method is only supported for effects inserted into
+     *       the input chain.
+     *
+     * @param device input device specification.
+     * @return retval operation completion status.
+     */
+    setInputDevice(bitfield<AudioDevice> device) generates (Result retval);
+
+    /**
+     * Read audio parameters configurations for input and output buffers.
+     *
+     * @return retval operation completion status.
+     * @return config configuration descriptor.
+     */
+    getConfig() generates (Result retval, EffectConfig config);
+
+    /**
+     * Read audio parameters configurations for input and output buffers of
+     * reverse stream.
+     *
+     * @return retval operation completion status.
+     * @return config configuration descriptor.
+     */
+    getConfigReverse() generates (Result retval, EffectConfig config);
+
+    /**
+     * Queries for supported combinations of main and auxiliary channels
+     * (e.g. for a multi-microphone noise suppressor).
+     *
+     * @param maxConfigs maximum number of the combinations to return.
+     * @return retval absence of the feature support is indicated using
+     *                NOT_SUPPORTED code. RESULT_TOO_BIG is returned if
+     *                the number of supported combinations exceeds 'maxConfigs'.
+     * @return result list of configuration descriptors.
+     */
+    getSupportedAuxChannelsConfigs(uint32_t maxConfigs)
+            generates (Result retval, vec<EffectAuxChannelsConfig> result);
+
+    /**
+     * Retrieves the current configuration of main and auxiliary channels.
+     *
+     * @return retval absence of the feature support is indicated using
+     *                NOT_SUPPORTED code.
+     * @return result configuration descriptor.
+     */
+    getAuxChannelsConfig()
+            generates (Result retval, EffectAuxChannelsConfig result);
+
+    /**
+     * Sets the current configuration of main and auxiliary channels.
+     *
+     * @return retval operation completion status; absence of the feature
+     *                support is indicated using NOT_SUPPORTED code.
+     */
+    setAuxChannelsConfig(EffectAuxChannelsConfig config)
+            generates (Result retval);
+
+    /**
+     * Set the audio source the capture path is configured for (Camcorder, voice
+     * recognition...).
+     *
+     * Note: this method is only supported for effects inserted into
+     *       the input chain.
+     *
+     * @param source source descriptor.
+     * @return retval operation completion status.
+     */
+    setAudioSource(AudioSource source) generates (Result retval);
+
+    /**
+     * This command indicates if the playback thread the effect is attached to
+     * is offloaded or not, and updates the I/O handle of the playback thread
+     * the effect is attached to.
+     *
+     * @param param effect offload descriptor.
+     * @return retval operation completion status.
+     */
+    offload(EffectOffloadParameter param) generates (Result retval);
+
+    /**
+     * Returns the effect descriptor.
+     *
+     * @return retval operation completion status.
+     * @return descriptor effect descriptor.
+     */
+    getDescriptor() generates (Result retval, EffectDescriptor descriptor);
+
+    /**
+     * Set up required transports for passing audio buffers to the effect.
+     *
+     * The transport consists of shared memory and a message queue for reporting
+     * effect processing operation status. The shared memory is set up
+     * separately using 'setProcessBuffers' method.
+     *
+     * Processing is requested by setting 'REQUEST_PROCESS' or
+     * 'REQUEST_PROCESS_REVERSE' EventFlags associated with the status message
+     * queue. The result of processing may be one of the following:
+     *   OK if there were no errors during processing;
+     *   INVALID_ARGUMENTS if audio buffers are invalid;
+     *   INVALID_STATE if the engine has finished the disable phase;
+     *   NOT_INITIALIZED if the audio buffers were not set;
+     *   NOT_SUPPORTED if the requested processing type is not supported by
+     *                 the effect.
+     *
+     * @return retval OK if both message queues were created successfully.
+     *                INVALID_STATE if the method was already called.
+     *                INVALID_ARGUMENTS if there was a problem setting up
+     *                                  the queue.
+     * @return statusMQ a message queue used for passing status from the effect.
+     */
+    @callflow(next={"setProcessBuffers"})
+    prepareForProcessing() generates (Result retval, fmq_sync<Result> statusMQ);
+
+    /**
+     * Set up input and output buffers for processing audio data. The effect
+     * may modify both the input and the output buffer during the operation.
+     * Buffers may be set multiple times during effect lifetime.
+     *
+     * The input and the output buffer may be reused between different effects,
+     * and the input buffer may be used as an output buffer. Buffers are
+     * distinguished using 'AudioBuffer.id' field.
+     *
+     * @param inBuffer input audio buffer.
+     * @param outBuffer output audio buffer.
+     * @return retval OK if both buffers were mapped successfully.
+     *                INVALID_ARGUMENTS if there was a problem with mapping
+     *                                  any of the buffers.
+     */
+    setProcessBuffers(AudioBuffer inBuffer, AudioBuffer outBuffer)
+            generates (Result retval);
+
+    /**
+     * Execute a vendor specific command on the effect. The command code
+     * and data, as well as result data are not interpreted by Android
+     * Framework and are passed as-is between the application and the effect.
+     *
+     * The effect must use standard POSIX.1-2001 error codes for the operation
+     * completion status.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it. This method only works for effects
+     * implemented in software.
+     *
+     * @param commandId the ID of the command.
+     * @param data command data.
+     * @param resultMaxSize maximum size in bytes of the result; can be 0.
+     * @return status command completion status.
+     * @return result result data.
+     */
+    command(uint32_t commandId, vec<uint8_t> data, uint32_t resultMaxSize)
+            generates (int32_t status, vec<uint8_t> result);
+
+    /**
+     * Set a vendor-specific parameter and apply it immediately. The parameter
+     * code and data are not interpreted by Android Framework and are passed
+     * as-is between the application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+     * unknown or if provided parameter data is invalid. If the effect does not
+     * support setting vendor-specific parameters, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it. This method only works for effects
+     * implemented in software.
+     *
+     * @param parameter identifying data of the parameter.
+     * @param value the value of the parameter.
+     * @return retval operation completion status.
+     */
+    setParameter(vec<uint8_t> parameter, vec<uint8_t> value)
+            generates (Result retval);
+
+    /**
+     * Get a vendor-specific parameter value. The parameter code and returned
+     * data are not interpreted by Android Framework and are passed as-is
+     * between the application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the parameter ID is
+     * unknown. If the effect does not support setting vendor-specific
+     * parameters, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param parameter identifying data of the parameter.
+     * @param valueMaxSize maximum size in bytes of the value.
+     * @return retval operation completion status.
+     * @return result the value of the parameter.
+     */
+    getParameter(vec<uint8_t> parameter, uint32_t valueMaxSize)
+            generates (Result retval, vec<uint8_t> value);
+
+    /**
+     * Get supported configs for a vendor-specific feature. The configs returned
+     * are not interpreted by Android Framework and are passed as-is between the
+     * application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+     * unknown. If the effect does not support getting vendor-specific feature
+     * configs, it must return NOT_SUPPORTED. If the feature is supported but
+     * the total number of supported configurations exceeds the maximum number
+     * indicated by the caller, the method must return RESULT_TOO_BIG.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param featureId feature identifier.
+     * @param maxConfigs maximum number of configs to return.
+     * @param configSize size of each config in bytes.
+     * @return retval operation completion status.
+     * @return configsCount number of configs returned.
+     * @return configsData data for all the configs returned.
+     */
+    getSupportedConfigsForFeature(
+            uint32_t featureId,
+            uint32_t maxConfigs,
+            uint32_t configSize) generates (
+                    Result retval,
+                    uint32_t configsCount,
+                    vec<uint8_t> configsData);
+
+    /**
+     * Get the current config for a vendor-specific feature. The config returned
+     * is not interpreted by Android Framework and is passed as-is between the
+     * application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+     * unknown. If the effect does not support getting vendor-specific
+     * feature configs, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param featureId feature identifier.
+     * @param configSize size of the config in bytes.
+     * @return retval operation completion status.
+     * @return configData config data.
+     */
+    getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize)
+            generates (Result retval, vec<uint8_t> configData);
+
+    /**
+     * Set the current config for a vendor-specific feature. The config data
+     * is not interpreted by Android Framework and is passed as-is between the
+     * application and the effect.
+     *
+     * The effect must use INVALID_ARGUMENTS return code if the feature ID is
+     * unknown. If the effect does not support getting vendor-specific
+     * feature configs, it must return NOT_SUPPORTED.
+     *
+     * Use this method only if the effect is provided by a third party, and
+     * there is no interface defined for it.  This method only works for effects
+     * implemented in software.
+     *
+     * @param featureId feature identifier.
+     * @param configData config data.
+     * @return retval operation completion status.
+     */
+    setCurrentConfigForFeature(uint32_t featureId, vec<uint8_t> configData)
+            generates (Result retval);
+
+    /**
+     * Called by the framework to deinitialize the effect and free up
+     * all the currently allocated resources. It is recommended to close
+     * the effect on the client side as soon as it is becomes unused.
+     *
+     * @return retval OK in case the success.
+     *                INVALID_STATE if the effect was already closed.
+     */
+    @exit
+    close() generates (Result retval);
+};
diff --git a/audio/effect/4.0/IEffectBufferProviderCallback.hal b/audio/effect/4.0/IEffectBufferProviderCallback.hal
new file mode 100644
index 0000000..439383b
--- /dev/null
+++ b/audio/effect/4.0/IEffectBufferProviderCallback.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+/**
+ * This callback interface contains functions that can be used by the effect
+ * engine 'process' function to exchange input and output audio buffers.
+ */
+interface IEffectBufferProviderCallback {
+    /**
+     * Called to retrieve a buffer where data should read from by 'process'
+     * function.
+     *
+     * @return buffer audio buffer for processing
+     */
+    getBuffer() generates (AudioBuffer buffer);
+
+    /**
+     * Called to provide a buffer with the data written by 'process' function.
+     *
+     * @param buffer audio buffer for processing
+     */
+    putBuffer(AudioBuffer buffer);
+};
diff --git a/audio/effect/4.0/IEffectsFactory.hal b/audio/effect/4.0/IEffectsFactory.hal
new file mode 100644
index 0000000..034af58
--- /dev/null
+++ b/audio/effect/4.0/IEffectsFactory.hal
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface IEffectsFactory {
+    /**
+     * Returns descriptors of different effects in all loaded libraries.
+     *
+     * @return retval operation completion status.
+     * @return result list of effect descriptors.
+     */
+    getAllDescriptors() generates(Result retval, vec<EffectDescriptor> result);
+
+    /**
+     * Returns a descriptor of a particular effect.
+     *
+     * @return retval operation completion status.
+     * @return result effect descriptor.
+     */
+    getDescriptor(Uuid uid) generates(Result retval, EffectDescriptor result);
+
+    /**
+     * Creates an effect engine of the specified type.  To release the effect
+     * engine, it is necessary to release references to the returned effect
+     * object.
+     *
+     * @param uid effect uuid.
+     * @param session audio session to which this effect instance will be
+     *                attached.  All effects created with the same session ID
+     *                are connected in series and process the same signal
+     *                stream.
+     * @param ioHandle identifies the output or input stream this effect is
+     *                 directed to in audio HAL.
+     * @return retval operation completion status.
+     * @return result the interface for the created effect.
+     * @return effectId the unique ID of the effect to be used with
+     *                  IStream::addEffect and IStream::removeEffect methods.
+     */
+    createEffect(Uuid uid, AudioSession session, AudioIoHandle ioHandle)
+        generates (Result retval, IEffect result, uint64_t effectId);
+};
diff --git a/audio/effect/4.0/IEnvironmentalReverbEffect.hal b/audio/effect/4.0/IEnvironmentalReverbEffect.hal
new file mode 100644
index 0000000..21264d2
--- /dev/null
+++ b/audio/effect/4.0/IEnvironmentalReverbEffect.hal
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface IEnvironmentalReverbEffect extends IEffect {
+    /**
+     * Sets whether the effect should be bypassed.
+     */
+    setBypass(bool bypass) generates (Result retval);
+
+    /**
+     * Gets whether the effect should be bypassed.
+     */
+    getBypass() generates (Result retval, bool bypass);
+
+    enum ParamRange : int16_t {
+        ROOM_LEVEL_MIN = -6000,
+        ROOM_LEVEL_MAX = 0,
+        ROOM_HF_LEVEL_MIN = -4000,
+        ROOM_HF_LEVEL_MAX = 0,
+        DECAY_TIME_MIN = 100,
+        DECAY_TIME_MAX = 20000,
+        DECAY_HF_RATIO_MIN = 100,
+        DECAY_HF_RATIO_MAX = 1000,
+        REFLECTIONS_LEVEL_MIN = -6000,
+        REFLECTIONS_LEVEL_MAX = 0,
+        REFLECTIONS_DELAY_MIN = 0,
+        REFLECTIONS_DELAY_MAX = 65,
+        REVERB_LEVEL_MIN = -6000,
+        REVERB_LEVEL_MAX = 0,
+        REVERB_DELAY_MIN = 0,
+        REVERB_DELAY_MAX = 65,
+        DIFFUSION_MIN = 0,
+        DIFFUSION_MAX = 1000,
+        DENSITY_MIN = 0,
+        DENSITY_MAX = 1000
+    };
+
+    /**
+     * Sets the room level.
+     */
+    setRoomLevel(int16_t roomLevel) generates (Result retval);
+
+    /**
+     * Gets the room level.
+     */
+    getRoomLevel() generates (Result retval, int16_t roomLevel);
+
+    /**
+     * Sets the room high frequencies level.
+     */
+    setRoomHfLevel(int16_t roomHfLevel) generates (Result retval);
+
+    /**
+     * Gets the room high frequencies level.
+     */
+    getRoomHfLevel() generates (Result retval, int16_t roomHfLevel);
+
+    /**
+     * Sets the room decay time.
+     */
+    setDecayTime(uint32_t decayTime) generates (Result retval);
+
+    /**
+     * Gets the room decay time.
+     */
+    getDecayTime() generates (Result retval, uint32_t decayTime);
+
+    /**
+     * Sets the ratio of high frequencies decay.
+     */
+    setDecayHfRatio(int16_t decayHfRatio) generates (Result retval);
+
+    /**
+     * Gets the ratio of high frequencies decay.
+     */
+    getDecayHfRatio() generates (Result retval, int16_t decayHfRatio);
+
+    /**
+     * Sets the level of reflections in the room.
+     */
+    setReflectionsLevel(int16_t reflectionsLevel) generates (Result retval);
+
+    /**
+     * Gets the level of reflections in the room.
+     */
+    getReflectionsLevel() generates (Result retval, int16_t reflectionsLevel);
+
+    /**
+     * Sets the reflections delay in the room.
+     */
+    setReflectionsDelay(uint32_t reflectionsDelay) generates (Result retval);
+
+    /**
+     * Gets the reflections delay in the room.
+     */
+    getReflectionsDelay() generates (Result retval, uint32_t reflectionsDelay);
+
+    /**
+     * Sets the reverb level of the room.
+     */
+    setReverbLevel(int16_t reverbLevel) generates (Result retval);
+
+    /**
+     * Gets the reverb level of the room.
+     */
+    getReverbLevel() generates (Result retval, int16_t reverbLevel);
+
+    /**
+     * Sets the reverb delay of the room.
+     */
+    setReverbDelay(uint32_t reverDelay) generates (Result retval);
+
+    /**
+     * Gets the reverb delay of the room.
+     */
+    getReverbDelay() generates (Result retval, uint32_t reverbDelay);
+
+    /**
+     * Sets room diffusion.
+     */
+    setDiffusion(int16_t diffusion) generates (Result retval);
+
+    /**
+     * Gets room diffusion.
+     */
+    getDiffusion() generates (Result retval, int16_t diffusion);
+
+    /**
+     * Sets room wall density.
+     */
+    setDensity(int16_t density) generates (Result retval);
+
+    /**
+     * Gets room wall density.
+     */
+    getDensity() generates (Result retval, int16_t density);
+
+    struct AllProperties {
+        int16_t  roomLevel;         // in millibels,    range -6000 to 0
+        int16_t  roomHfLevel;       // in millibels,    range -4000 to 0
+        uint32_t decayTime;         // in milliseconds, range 100 to 20000
+        int16_t  decayHfRatio;      // in permilles,    range 100 to 1000
+        int16_t  reflectionsLevel;  // in millibels,    range -6000 to 0
+        uint32_t reflectionsDelay;  // in milliseconds, range 0 to 65
+        int16_t  reverbLevel;       // in millibels,    range -6000 to 0
+        uint32_t reverbDelay;       // in milliseconds, range 0 to 65
+        int16_t  diffusion;         // in permilles,    range 0 to 1000
+        int16_t  density;           // in permilles,    range 0 to 1000
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/4.0/IEqualizerEffect.hal b/audio/effect/4.0/IEqualizerEffect.hal
new file mode 100644
index 0000000..58f2b73
--- /dev/null
+++ b/audio/effect/4.0/IEqualizerEffect.hal
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface IEqualizerEffect extends IEffect {
+    /**
+     * Gets the number of frequency bands that the equalizer supports.
+     */
+    getNumBands() generates (Result retval, uint16_t numBands);
+
+    /**
+     * Returns the minimum and maximum band levels supported.
+     */
+    getLevelRange()
+            generates (Result retval, int16_t minLevel, int16_t maxLevel);
+
+    /**
+     * Sets the gain for the given equalizer band.
+     */
+    setBandLevel(uint16_t band, int16_t level) generates (Result retval);
+
+    /**
+     * Gets the gain for the given equalizer band.
+     */
+    getBandLevel(uint16_t band) generates (Result retval, int16_t level);
+
+    /**
+     * Gets the center frequency of the given band, in milliHertz.
+     */
+    getBandCenterFrequency(uint16_t band)
+            generates (Result retval, uint32_t centerFreqmHz);
+
+    /**
+     * Gets the frequency range of the given frequency band, in milliHertz.
+     */
+    getBandFrequencyRange(uint16_t band)
+            generates (Result retval, uint32_t minFreqmHz, uint32_t maxFreqmHz);
+
+    /**
+     * Gets the band that has the most effect on the given frequency
+     * in milliHertz.
+     */
+    getBandForFrequency(uint32_t freqmHz)
+            generates (Result retval, uint16_t band);
+
+    /**
+     * Gets the names of all presets the equalizer supports.
+     */
+    getPresetNames() generates (Result retval, vec<string> names);
+
+    /**
+     * Sets the current preset using the index of the preset in the names
+     * vector returned via 'getPresetNames'.
+     */
+    setCurrentPreset(uint16_t preset) generates (Result retval);
+
+    /**
+     * Gets the current preset.
+     */
+    getCurrentPreset() generates (Result retval, uint16_t preset);
+
+    struct AllProperties {
+        uint16_t curPreset;
+        vec<int16_t> bandLevels;
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/4.0/ILoudnessEnhancerEffect.hal b/audio/effect/4.0/ILoudnessEnhancerEffect.hal
new file mode 100644
index 0000000..2421834
--- /dev/null
+++ b/audio/effect/4.0/ILoudnessEnhancerEffect.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface ILoudnessEnhancerEffect extends IEffect {
+    /**
+     * Sets target gain expressed in millibels.
+     */
+    setTargetGain(int32_t targetGainMb) generates (Result retval);
+
+    /**
+     * Gets target gain expressed in millibels.
+     */
+    getTargetGain() generates (Result retval, int32_t targetGainMb);
+};
diff --git a/audio/effect/4.0/INoiseSuppressionEffect.hal b/audio/effect/4.0/INoiseSuppressionEffect.hal
new file mode 100644
index 0000000..ce593a0
--- /dev/null
+++ b/audio/effect/4.0/INoiseSuppressionEffect.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface INoiseSuppressionEffect extends IEffect {
+    enum Level : int32_t {
+        LOW,
+        MEDIUM,
+        HIGH
+    };
+
+    /**
+     * Sets suppression level.
+     */
+    setSuppressionLevel(Level level) generates (Result retval);
+
+    /**
+     * Gets suppression level.
+     */
+    getSuppressionLevel() generates (Result retval, Level level);
+
+    enum Type : int32_t {
+        SINGLE_CHANNEL,
+        MULTI_CHANNEL
+    };
+
+    /**
+     * Set suppression type.
+     */
+    setSuppressionType(Type type) generates (Result retval);
+
+    /**
+     * Get suppression type.
+     */
+    getSuppressionType() generates (Result retval, Type type);
+
+    struct AllProperties {
+        Level level;
+        Type type;
+    };
+
+    /**
+     * Sets all properties at once.
+     */
+    setAllProperties(AllProperties properties) generates (Result retval);
+
+    /**
+     * Gets all properties at once.
+     */
+    getAllProperties() generates (Result retval, AllProperties properties);
+};
diff --git a/audio/effect/4.0/IPresetReverbEffect.hal b/audio/effect/4.0/IPresetReverbEffect.hal
new file mode 100644
index 0000000..2417235
--- /dev/null
+++ b/audio/effect/4.0/IPresetReverbEffect.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface IPresetReverbEffect extends IEffect {
+    enum Preset : int32_t {
+        NONE,        // no reverb or reflections
+        SMALLROOM,   // a small room less than five meters in length
+        MEDIUMROOM,  // a medium room with a length of ten meters or less
+        LARGEROOM,   // a large-sized room suitable for live performances
+        MEDIUMHALL,  // a medium-sized hall
+        LARGEHALL,   // a large-sized hall suitable for a full orchestra
+        PLATE,       // synthesis of the traditional plate reverb
+        LAST = PLATE
+    };
+
+    /**
+     * Sets the current preset.
+     */
+    setPreset(Preset preset) generates (Result retval);
+
+    /**
+     * Gets the current preset.
+     */
+    getPreset() generates (Result retval, Preset preset);
+};
diff --git a/audio/effect/4.0/IVirtualizerEffect.hal b/audio/effect/4.0/IVirtualizerEffect.hal
new file mode 100644
index 0000000..52038ca
--- /dev/null
+++ b/audio/effect/4.0/IVirtualizerEffect.hal
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface IVirtualizerEffect extends IEffect {
+    /**
+     * Returns whether setting virtualization strength is supported.
+     */
+    isStrengthSupported() generates (bool strengthSupported);
+
+    enum StrengthRange : uint16_t {
+        MIN = 0,
+        MAX = 1000
+    };
+
+    /**
+     * Sets virtualization strength.
+     *
+     * @param strength strength of the effect. The valid range for strength
+     *                 strength is [0, 1000], where 0 per mille designates the
+     *                 mildest effect and 1000 per mille designates the
+     *                 strongest.
+     * @return retval operation completion status.
+     */
+    setStrength(uint16_t strength) generates (Result retval);
+
+    /**
+     * Gets virtualization strength.
+     */
+    getStrength() generates (Result retval, uint16_t strength);
+
+    struct SpeakerAngle {
+        /** Speaker channel mask */
+        bitfield<AudioChannelMask> mask;
+        // all angles are expressed in degrees and
+        // are relative to the listener.
+        int16_t azimuth; // 0 is the direction the listener faces
+                         // 180 is behind the listener
+                         // -90 is to their left
+        int16_t elevation; // 0 is the horizontal plane
+                           // +90 is above the listener, -90 is below
+    };
+    /**
+     * Retrieves virtual speaker angles for the given channel mask on the
+     * specified device.
+     */
+    getVirtualSpeakerAngles(bitfield<AudioChannelMask> mask, AudioDevice device)
+            generates (Result retval, vec<SpeakerAngle> speakerAngles);
+
+    /**
+     * Forces the virtualizer effect for the given output device.
+     */
+    forceVirtualizationMode(AudioDevice device) generates (Result retval);
+
+    /**
+     * Returns audio device reflecting the current virtualization mode,
+     * AUDIO_DEVICE_NONE when not virtualizing.
+     */
+    getVirtualizationMode() generates (Result retval, AudioDevice device);
+};
diff --git a/audio/effect/4.0/IVisualizerEffect.hal b/audio/effect/4.0/IVisualizerEffect.hal
new file mode 100644
index 0000000..2fee980
--- /dev/null
+++ b/audio/effect/4.0/IVisualizerEffect.hal
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+import IEffect;
+
+interface IVisualizerEffect extends IEffect {
+    enum CaptureSizeRange : int32_t {
+        MAX = 1024,  // maximum capture size in samples
+        MIN = 128    // minimum capture size in samples
+    };
+
+    /**
+     * Sets the number PCM samples in the capture.
+     */
+    setCaptureSize(uint16_t captureSize) generates (Result retval);
+
+    /**
+     * Gets the number PCM samples in the capture.
+     */
+    getCaptureSize() generates (Result retval, uint16_t captureSize);
+
+    enum ScalingMode : int32_t {
+        // Keep in sync with SCALING_MODE_... in
+        // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+        NORMALIZED = 0,
+        AS_PLAYED = 1
+    };
+
+    /**
+     * Specifies the way the captured data is scaled.
+     */
+    setScalingMode(ScalingMode scalingMode) generates (Result retval);
+
+    /**
+     * Retrieves the way the captured data is scaled.
+     */
+    getScalingMode() generates (Result retval, ScalingMode scalingMode);
+
+    /**
+     * Informs the visualizer about the downstream latency.
+     */
+    setLatency(uint32_t latencyMs) generates (Result retval);
+
+    /**
+     * Gets the downstream latency.
+     */
+    getLatency() generates (Result retval, uint32_t latencyMs);
+
+    enum MeasurementMode : int32_t {
+        // Keep in sync with MEASUREMENT_MODE_... in
+        // frameworks/base/media/java/android/media/audiofx/Visualizer.java
+        NONE = 0x0,
+        PEAK_RMS = 0x1
+    };
+
+    /**
+     * Specifies which measurements are to be made.
+     */
+    setMeasurementMode(MeasurementMode measurementMode)
+            generates (Result retval);
+
+    /**
+     * Retrieves which measurements are to be made.
+     */
+    getMeasurementMode() generates (
+            Result retval, MeasurementMode measurementMode);
+
+    /**
+     * Retrieves the latest PCM snapshot captured by the visualizer engine.  The
+     * number of samples to capture is specified by 'setCaptureSize' parameter.
+     *
+     * @return retval operation completion status.
+     * @return samples samples in 8 bit unsigned format (0 = 0x80)
+     */
+    capture() generates (Result retval, vec<uint8_t> samples);
+
+    struct Measurement {
+        MeasurementMode mode;    // discriminator
+        union Values {
+            struct PeakAndRms {
+                int32_t peakMb;  // millibels
+                int32_t rmsMb;   // millibels
+            } peakAndRms;
+        } value;
+    };
+    /**
+     * Retrieves the latest measurements. The measurements to be made
+     * are specified by 'setMeasurementMode' parameter.
+     *
+     * @return retval operation completion status.
+     * @return result measurement.
+     */
+    measure() generates (Result retval, Measurement result);
+};
diff --git a/audio/effect/4.0/types.hal b/audio/effect/4.0/types.hal
new file mode 100644
index 0000000..0f76601
--- /dev/null
+++ b/audio/effect/4.0/types.hal
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.effect@4.0;
+
+import android.hardware.audio.common@4.0;
+
+enum Result : int32_t {
+    OK,
+    NOT_INITIALIZED,
+    INVALID_ARGUMENTS,
+    INVALID_STATE,
+    NOT_SUPPORTED,
+    RESULT_TOO_BIG
+};
+
+/**
+ * Effect engine capabilities/requirements flags.
+ *
+ * Definitions for flags field of effect descriptor.
+ *
+ * +----------------+--------+--------------------------------------------------
+ * | description    | bits   | values
+ * +----------------+--------+--------------------------------------------------
+ * | connection     | 0..2   | 0 insert: after track process
+ * | mode           |        | 1 auxiliary: connect to track auxiliary
+ * |                |        |  output and use send level
+ * |                |        | 2 replace: replaces track process function;
+ * |                |        |   must implement SRC, volume and mono to stereo.
+ * |                |        | 3 pre processing: applied below audio HAL on in
+ * |                |        | 4 post processing: applied below audio HAL on out
+ * |                |        | 5 - 7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | insertion      | 3..5   | 0 none
+ * | preference     |        | 1 first of the chain
+ * |                |        | 2 last of the chain
+ * |                |        | 3 exclusive (only effect in the insert chain)
+ * |                |        | 4..7 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Volume         | 6..8   | 0 none
+ * | management     |        | 1 implements volume control
+ * |                |        | 2 requires volume indication
+ * |                |        | 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Device         | 9..11  | 0 none
+ * | indication     |        | 1 requires device updates
+ * |                |        | 2, 4 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Sample input   | 12..13 | 1 direct: process() function or
+ * | mode           |        |   EFFECT_CMD_SET_CONFIG command must specify
+ * |                |        |   a buffer descriptor
+ * |                |        | 2 provider: process() function uses the
+ * |                |        |   bufferProvider indicated by the
+ * |                |        |   EFFECT_CMD_SET_CONFIG command to request input.
+ * |                |        |   buffers.
+ * |                |        | 3 both: both input modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Sample output  | 14..15 | 1 direct: process() function or
+ * | mode           |        |   EFFECT_CMD_SET_CONFIG command must specify
+ * |                |        |   a buffer descriptor
+ * |                |        | 2 provider: process() function uses the
+ * |                |        |   bufferProvider indicated by the
+ * |                |        |   EFFECT_CMD_SET_CONFIG command to request output
+ * |                |        |   buffers.
+ * |                |        | 3 both: both output modes are supported
+ * +----------------+--------+--------------------------------------------------
+ * | Hardware       | 16..17 | 0 No hardware acceleration
+ * | acceleration   |        | 1 non tunneled hw acceleration: the process()
+ * |                |        |   function reads the samples, send them to HW
+ * |                |        |   accelerated effect processor, reads back
+ * |                |        |   the processed samples and returns them
+ * |                |        |   to the output buffer.
+ * |                |        | 2 tunneled hw acceleration: the process()
+ * |                |        |   function is transparent. The effect interface
+ * |                |        |   is only used to control the effect engine.
+ * |                |        |   This mode is relevant for global effects
+ * |                |        |   actually applied by the audio hardware on
+ * |                |        |   the output stream.
+ * +----------------+--------+--------------------------------------------------
+ * | Audio Mode     | 18..19 | 0 none
+ * | indication     |        | 1 requires audio mode updates
+ * |                |        | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Audio source   | 20..21 | 0 none
+ * | indication     |        | 1 requires audio source updates
+ * |                |        | 2..3 reserved
+ * +----------------+--------+--------------------------------------------------
+ * | Effect offload | 22     | 0 The effect cannot be offloaded to an audio DSP
+ * | supported      |        | 1 The effect can be offloaded to an audio DSP
+ * +----------------+--------+--------------------------------------------------
+ * | Process        | 23     | 0 The effect implements a process function.
+ * | function       |        | 1 The effect does not implement a process
+ * | not            |        |   function: enabling the effect has no impact
+ * | implemented    |        |   on latency or CPU load.
+ * |                |        |   Effect implementations setting this flag do not
+ * |                |        |   have to implement a process function.
+ * +----------------+--------+--------------------------------------------------
+ */
+@export(name="", value_prefix="EFFECT_FLAG_")
+enum EffectFlags : int32_t {
+    // Insert mode
+    TYPE_SHIFT = 0,
+    TYPE_SIZE = 3,
+    TYPE_MASK = ((1 << TYPE_SIZE) -1) << TYPE_SHIFT,
+    TYPE_INSERT = 0 << TYPE_SHIFT,
+    TYPE_AUXILIARY = 1 << TYPE_SHIFT,
+    TYPE_REPLACE = 2 << TYPE_SHIFT,
+    TYPE_PRE_PROC = 3 << TYPE_SHIFT,
+    TYPE_POST_PROC = 4 << TYPE_SHIFT,
+
+    // Insert preference
+    INSERT_SHIFT = TYPE_SHIFT + TYPE_SIZE,
+    INSERT_SIZE = 3,
+    INSERT_MASK = ((1 << INSERT_SIZE) -1) << INSERT_SHIFT,
+    INSERT_ANY = 0 << INSERT_SHIFT,
+    INSERT_FIRST = 1 << INSERT_SHIFT,
+    INSERT_LAST = 2 << INSERT_SHIFT,
+    INSERT_EXCLUSIVE = 3 << INSERT_SHIFT,
+
+    // Volume control
+    VOLUME_SHIFT = INSERT_SHIFT + INSERT_SIZE,
+    VOLUME_SIZE = 3,
+    VOLUME_MASK = ((1 << VOLUME_SIZE) -1) << VOLUME_SHIFT,
+    VOLUME_CTRL = 1 << VOLUME_SHIFT,
+    VOLUME_IND = 2 << VOLUME_SHIFT,
+    VOLUME_NONE = 0 << VOLUME_SHIFT,
+
+    // Device indication
+    DEVICE_SHIFT = VOLUME_SHIFT + VOLUME_SIZE,
+    DEVICE_SIZE = 3,
+    DEVICE_MASK = ((1 << DEVICE_SIZE) -1) << DEVICE_SHIFT,
+    DEVICE_IND = 1 << DEVICE_SHIFT,
+    DEVICE_NONE = 0 << DEVICE_SHIFT,
+
+    // Sample input modes
+    INPUT_SHIFT = DEVICE_SHIFT + DEVICE_SIZE,
+    INPUT_SIZE = 2,
+    INPUT_MASK = ((1 << INPUT_SIZE) -1) << INPUT_SHIFT,
+    INPUT_DIRECT = 1 << INPUT_SHIFT,
+    INPUT_PROVIDER = 2 << INPUT_SHIFT,
+    INPUT_BOTH = 3 << INPUT_SHIFT,
+
+    // Sample output modes
+    OUTPUT_SHIFT = INPUT_SHIFT + INPUT_SIZE,
+    OUTPUT_SIZE = 2,
+    OUTPUT_MASK = ((1 << OUTPUT_SIZE) -1) << OUTPUT_SHIFT,
+    OUTPUT_DIRECT = 1 << OUTPUT_SHIFT,
+    OUTPUT_PROVIDER = 2 << OUTPUT_SHIFT,
+    OUTPUT_BOTH = 3 << OUTPUT_SHIFT,
+
+    // Hardware acceleration mode
+    HW_ACC_SHIFT = OUTPUT_SHIFT + OUTPUT_SIZE,
+    HW_ACC_SIZE = 2,
+    HW_ACC_MASK = ((1 << HW_ACC_SIZE) -1) << HW_ACC_SHIFT,
+    HW_ACC_SIMPLE = 1 << HW_ACC_SHIFT,
+    HW_ACC_TUNNEL = 2 << HW_ACC_SHIFT,
+
+    // Audio mode indication
+    AUDIO_MODE_SHIFT = HW_ACC_SHIFT + HW_ACC_SIZE,
+    AUDIO_MODE_SIZE = 2,
+    AUDIO_MODE_MASK = ((1 << AUDIO_MODE_SIZE) -1) << AUDIO_MODE_SHIFT,
+    AUDIO_MODE_IND = 1 << AUDIO_MODE_SHIFT,
+    AUDIO_MODE_NONE = 0 << AUDIO_MODE_SHIFT,
+
+    // Audio source indication
+    AUDIO_SOURCE_SHIFT = AUDIO_MODE_SHIFT + AUDIO_MODE_SIZE,
+    AUDIO_SOURCE_SIZE = 2,
+    AUDIO_SOURCE_MASK = ((1 << AUDIO_SOURCE_SIZE) -1) << AUDIO_SOURCE_SHIFT,
+    AUDIO_SOURCE_IND = 1 << AUDIO_SOURCE_SHIFT,
+    AUDIO_SOURCE_NONE = 0 << AUDIO_SOURCE_SHIFT,
+
+    // Effect offload indication
+    OFFLOAD_SHIFT = AUDIO_SOURCE_SHIFT + AUDIO_SOURCE_SIZE,
+    OFFLOAD_SIZE = 1,
+    OFFLOAD_MASK = ((1 << OFFLOAD_SIZE) -1) << OFFLOAD_SHIFT,
+    OFFLOAD_SUPPORTED = 1 << OFFLOAD_SHIFT,
+
+    // Effect has no process indication
+    NO_PROCESS_SHIFT = OFFLOAD_SHIFT + OFFLOAD_SIZE,
+    NO_PROCESS_SIZE = 1,
+    NO_PROCESS_MASK = ((1 << NO_PROCESS_SIZE) -1) << NO_PROCESS_SHIFT,
+    NO_PROCESS = 1 << NO_PROCESS_SHIFT
+};
+
+/**
+ * The effect descriptor contains necessary information to facilitate the
+ * enumeration of the effect engines present in a library.
+ */
+struct EffectDescriptor {
+    Uuid type;             // UUID of to the OpenSL ES interface implemented
+                           // by this effect
+    Uuid uuid;             // UUID for this particular implementation
+    EffectFlags flags;     // effect engine capabilities/requirements flags
+    uint16_t cpuLoad;      // CPU load indication expressed in 0.1 MIPS units
+                           // as estimated on an ARM9E core (ARMv5TE) with 0 WS
+    uint16_t memoryUsage;  // data memory usage expressed in KB and includes
+                           // only dynamically allocated memory
+    uint8_t[64] name;      // human readable effect name
+    uint8_t[64] implementor;  // human readable effect implementor name
+};
+
+/**
+ * A buffer is a chunk of audio data for processing.  Multi-channel audio is
+ * always interleaved. The channel order is from LSB to MSB with regard to the
+ * channel mask definition in audio.h, audio_channel_mask_t, e.g.:
+ * Stereo: L, R; 5.1: FL, FR, FC, LFE, BL, BR.
+ *
+ * The buffer size is expressed in frame count, a frame being composed of
+ * samples for all channels at a given time. Frame size for unspecified format
+ * (AUDIO_FORMAT_OTHER) is 8 bit by definition.
+ */
+struct AudioBuffer {
+    uint64_t id;
+    uint32_t frameCount;
+    memory data;
+};
+
+@export(name="effect_buffer_access_e", value_prefix="EFFECT_BUFFER_")
+enum EffectBufferAccess : int32_t {
+    ACCESS_WRITE,
+    ACCESS_READ,
+    ACCESS_ACCUMULATE
+};
+
+/**
+ * Determines what fields of EffectBufferConfig need to be considered.
+ */
+@export(name="", value_prefix="EFFECT_CONFIG_")
+enum EffectConfigParameters : int32_t {
+    BUFFER = 0x0001,    // buffer field
+    SMP_RATE = 0x0002,  // samplingRate
+    CHANNELS = 0x0004,  // channels
+    FORMAT = 0x0008,    // format
+    ACC_MODE = 0x0010,  // accessMode
+    // Note that the 2.0 ALL have been moved to an helper function
+};
+
+/**
+ * The buffer config structure specifies the input or output audio format
+ * to be used by the effect engine.
+ */
+struct EffectBufferConfig {
+    AudioBuffer buffer;
+    uint32_t samplingRateHz;
+    bitfield<AudioChannelMask> channels;
+    AudioFormat format;
+    EffectBufferAccess accessMode;
+    bitfield<EffectConfigParameters> mask;
+};
+
+struct EffectConfig {
+    EffectBufferConfig inputCfg;
+    EffectBufferConfig outputCfg;
+};
+
+@export(name="effect_feature_e", value_prefix="EFFECT_FEATURE_")
+enum EffectFeature : int32_t {
+    AUX_CHANNELS, // supports auxiliary channels
+                  // (e.g. dual mic noise suppressor)
+    CNT
+};
+
+struct EffectAuxChannelsConfig {
+    bitfield<AudioChannelMask> mainChannels;  // channel mask for main channels
+    bitfield<AudioChannelMask> auxChannels;   // channel mask for auxiliary channels
+};
+
+struct EffectOffloadParameter {
+    bool isOffload;          // true if the playback thread the effect
+                             // is attached to is offloaded
+    AudioIoHandle ioHandle;  // io handle of the playback thread
+                             // the effect is attached to
+};
+
+/**
+ * The message queue flags used to synchronize reads and writes from
+ * the status message queue used by effects.
+ */
+enum MessageQueueFlagBits : uint32_t {
+    DONE_PROCESSING = 1 << 0,
+    REQUEST_PROCESS = 1 << 1,
+    REQUEST_PROCESS_REVERSE = 1 << 2,
+    REQUEST_QUIT = 1 << 3,
+    REQUEST_PROCESS_ALL =
+        REQUEST_PROCESS | REQUEST_PROCESS_REVERSE | REQUEST_QUIT
+};
diff --git a/audio/2.0/default/OWNERS b/audio/effect/all-versions/OWNERS
similarity index 100%
rename from audio/2.0/default/OWNERS
rename to audio/effect/all-versions/OWNERS
diff --git a/audio/effect/all-versions/default/Android.bp b/audio/effect/all-versions/default/Android.bp
new file mode 100644
index 0000000..ed2a093
--- /dev/null
+++ b/audio/effect/all-versions/default/Android.bp
@@ -0,0 +1,31 @@
+cc_library_headers {
+    name: "android.hardware.audio.effect@all-versions-impl",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+
+    export_include_dirs: ["include"],
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libeffects",
+        "libfmq",
+        "libhidlbase",
+        "libhidlmemory",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "android.hardware.audio.common-util",
+        "android.hidl.memory@1.0",
+    ],
+
+    header_libs: [
+        "libaudio_system_headers",
+        "libaudioclient_headers",
+        "libeffects_headers",
+        "libhardware_headers",
+        "libmedia_headers",
+        "android.hardware.audio.common.util@all-versions",
+    ],
+}
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.h
new file mode 100644
index 0000000..b63f2fb
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.h
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAcousticEchoCancelerEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct AcousticEchoCancelerEffect : public IAcousticEchoCancelerEffect {
+    explicit AcousticEchoCancelerEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from
+    // ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAcousticEchoCancelerEffect follow.
+    Return<Result> setEchoDelay(uint32_t echoDelayMs) override;
+    Return<void> getEchoDelay(getEchoDelay_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+
+    virtual ~AcousticEchoCancelerEffect();
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.impl.h
new file mode 100644
index 0000000..bee3607
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/AcousticEchoCancelerEffect.impl.h
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <android/log.h>
+#include <system/audio_effects/effect_aec.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+AcousticEchoCancelerEffect::AcousticEchoCancelerEffect(effect_handle_t handle)
+    : mEffect(new Effect(handle)) {}
+
+AcousticEchoCancelerEffect::~AcousticEchoCancelerEffect() {}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> AcousticEchoCancelerEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> AcousticEchoCancelerEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> AcousticEchoCancelerEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> AcousticEchoCancelerEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> AcousticEchoCancelerEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> AcousticEchoCancelerEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> AcousticEchoCancelerEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                                         setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> AcousticEchoCancelerEffect::volumeChangeNotification(
+    const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> AcousticEchoCancelerEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setAuxChannelsConfig(
+    const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> AcousticEchoCancelerEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> AcousticEchoCancelerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                             const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> AcousticEchoCancelerEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                                 uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                                        const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> AcousticEchoCancelerEffect::getParameter(const hidl_vec<uint8_t>& parameter,
+                                                      uint32_t valueMaxSize,
+                                                      getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> AcousticEchoCancelerEffect::getCurrentConfigForFeature(
+    uint32_t featureId, uint32_t configSize, getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> AcousticEchoCancelerEffect::setCurrentConfigForFeature(
+    uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> AcousticEchoCancelerEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAcousticEchoCancelerEffect
+// follow.
+Return<Result> AcousticEchoCancelerEffect::setEchoDelay(uint32_t echoDelayMs) {
+    return mEffect->setParam(AEC_PARAM_ECHO_DELAY, echoDelayMs);
+}
+
+Return<void> AcousticEchoCancelerEffect::getEchoDelay(getEchoDelay_cb _hidl_cb) {
+    return mEffect->getIntegerParam(AEC_PARAM_ECHO_DELAY, _hidl_cb);
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.h b/audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.h
new file mode 100644
index 0000000..34dea2d
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <mutex>
+
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <system/audio_effect.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <utils/Singleton.h>
+
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer;
+using ::android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+class AudioBufferWrapper : public RefBase {
+   public:
+    explicit AudioBufferWrapper(const AudioBuffer& buffer);
+    virtual ~AudioBufferWrapper();
+    bool init();
+    audio_buffer_t* getHalBuffer() { return &mHalBuffer; }
+
+   private:
+    AudioBufferWrapper(const AudioBufferWrapper&) = delete;
+    void operator=(AudioBufferWrapper) = delete;
+
+    AudioBuffer mHidlBuffer;
+    sp<IMemory> mHidlMemory;
+    audio_buffer_t mHalBuffer;
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
+
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::implementation::AudioBufferWrapper;
+
+namespace android {
+
+// This class needs to be in 'android' ns because Singleton macros require that.
+class AudioBufferManager : public Singleton<AudioBufferManager> {
+   public:
+    bool wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper);
+
+   private:
+    friend class hardware::audio::effect::AUDIO_HAL_VERSION::implementation::AudioBufferWrapper;
+
+    // Called by AudioBufferWrapper.
+    void removeEntry(uint64_t id);
+
+    std::mutex mLock;
+    KeyedVector<uint64_t, wp<AudioBufferWrapper>> mBuffers;
+};
+
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.impl.h
new file mode 100644
index 0000000..71ccd2d
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/AudioBufferManager.impl.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <atomic>
+
+#include <hidlmemory/mapping.h>
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(AudioBufferManager);
+
+bool AudioBufferManager::wrap(const AudioBuffer& buffer, sp<AudioBufferWrapper>* wrapper) {
+    // Check if we have this buffer already
+    std::lock_guard<std::mutex> lock(mLock);
+    ssize_t idx = mBuffers.indexOfKey(buffer.id);
+    if (idx >= 0) {
+        *wrapper = mBuffers[idx].promote();
+        if (*wrapper != nullptr) {
+            (*wrapper)->getHalBuffer()->frameCount = buffer.frameCount;
+            return true;
+        }
+        mBuffers.removeItemsAt(idx);
+    }
+    // Need to create and init a new AudioBufferWrapper.
+    sp<AudioBufferWrapper> tempBuffer(new AudioBufferWrapper(buffer));
+    if (!tempBuffer->init()) return false;
+    *wrapper = tempBuffer;
+    mBuffers.add(buffer.id, *wrapper);
+    return true;
+}
+
+void AudioBufferManager::removeEntry(uint64_t id) {
+    std::lock_guard<std::mutex> lock(mLock);
+    ssize_t idx = mBuffers.indexOfKey(id);
+    if (idx >= 0) mBuffers.removeItemsAt(idx);
+}
+
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+AudioBufferWrapper::AudioBufferWrapper(const AudioBuffer& buffer)
+    : mHidlBuffer(buffer), mHalBuffer{0, {nullptr}} {}
+
+AudioBufferWrapper::~AudioBufferWrapper() {
+    AudioBufferManager::getInstance().removeEntry(mHidlBuffer.id);
+}
+
+bool AudioBufferWrapper::init() {
+    if (mHalBuffer.raw != nullptr) {
+        ALOGE("An attempt to init AudioBufferWrapper twice");
+        return false;
+    }
+    mHidlMemory = mapMemory(mHidlBuffer.data);
+    if (mHidlMemory == nullptr) {
+        ALOGE("Could not map HIDL memory to IMemory");
+        return false;
+    }
+    mHalBuffer.raw = static_cast<void*>(mHidlMemory->getPointer());
+    if (mHalBuffer.raw == nullptr) {
+        ALOGE("IMemory buffer pointer is null");
+        return false;
+    }
+    mHalBuffer.frameCount = mHidlBuffer.frameCount;
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.h
new file mode 100644
index 0000000..941f45d
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <system/audio_effects/effect_agc.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAutomaticGainControlEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct AutomaticGainControlEffect : public IAutomaticGainControlEffect {
+    explicit AutomaticGainControlEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from
+    // ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAutomaticGainControlEffect follow.
+    Return<Result> setTargetLevel(int16_t targetLevelMb) override;
+    Return<void> getTargetLevel(getTargetLevel_cb _hidl_cb) override;
+    Return<Result> setCompGain(int16_t compGainMb) override;
+    Return<void> getCompGain(getCompGain_cb _hidl_cb) override;
+    Return<Result> setLimiterEnabled(bool enabled) override;
+    Return<void> isLimiterEnabled(isLimiterEnabled_cb _hidl_cb) override;
+    Return<Result> setAllProperties(
+        const IAutomaticGainControlEffect::AllProperties& properties) override;
+    Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+
+    virtual ~AutomaticGainControlEffect();
+
+    void propertiesFromHal(const t_agc_settings& halProperties,
+                           IAutomaticGainControlEffect::AllProperties* properties);
+    void propertiesToHal(const IAutomaticGainControlEffect::AllProperties& properties,
+                         t_agc_settings* halProperties);
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.impl.h
new file mode 100644
index 0000000..af05d9b
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/AutomaticGainControlEffect.impl.h
@@ -0,0 +1,224 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <android/log.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+AutomaticGainControlEffect::AutomaticGainControlEffect(effect_handle_t handle)
+    : mEffect(new Effect(handle)) {}
+
+AutomaticGainControlEffect::~AutomaticGainControlEffect() {}
+
+void AutomaticGainControlEffect::propertiesFromHal(
+    const t_agc_settings& halProperties, IAutomaticGainControlEffect::AllProperties* properties) {
+    properties->targetLevelMb = halProperties.targetLevel;
+    properties->compGainMb = halProperties.compGain;
+    properties->limiterEnabled = halProperties.limiterEnabled;
+}
+
+void AutomaticGainControlEffect::propertiesToHal(
+    const IAutomaticGainControlEffect::AllProperties& properties, t_agc_settings* halProperties) {
+    halProperties->targetLevel = properties.targetLevelMb;
+    halProperties->compGain = properties.compGainMb;
+    halProperties->limiterEnabled = properties.limiterEnabled;
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> AutomaticGainControlEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> AutomaticGainControlEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> AutomaticGainControlEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> AutomaticGainControlEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> AutomaticGainControlEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> AutomaticGainControlEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> AutomaticGainControlEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                                         setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::volumeChangeNotification(
+    const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> AutomaticGainControlEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> AutomaticGainControlEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> AutomaticGainControlEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> AutomaticGainControlEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setAuxChannelsConfig(
+    const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> AutomaticGainControlEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> AutomaticGainControlEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> AutomaticGainControlEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                             const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> AutomaticGainControlEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                                 uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                                        const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> AutomaticGainControlEffect::getParameter(const hidl_vec<uint8_t>& parameter,
+                                                      uint32_t valueMaxSize,
+                                                      getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> AutomaticGainControlEffect::getCurrentConfigForFeature(
+    uint32_t featureId, uint32_t configSize, getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setCurrentConfigForFeature(
+    uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> AutomaticGainControlEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IAutomaticGainControlEffect
+// follow.
+Return<Result> AutomaticGainControlEffect::setTargetLevel(int16_t targetLevelMb) {
+    return mEffect->setParam(AGC_PARAM_TARGET_LEVEL, targetLevelMb);
+}
+
+Return<void> AutomaticGainControlEffect::getTargetLevel(getTargetLevel_cb _hidl_cb) {
+    return mEffect->getIntegerParam(AGC_PARAM_TARGET_LEVEL, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setCompGain(int16_t compGainMb) {
+    return mEffect->setParam(AGC_PARAM_COMP_GAIN, compGainMb);
+}
+
+Return<void> AutomaticGainControlEffect::getCompGain(getCompGain_cb _hidl_cb) {
+    return mEffect->getIntegerParam(AGC_PARAM_COMP_GAIN, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setLimiterEnabled(bool enabled) {
+    return mEffect->setParam(AGC_PARAM_LIMITER_ENA, enabled);
+}
+
+Return<void> AutomaticGainControlEffect::isLimiterEnabled(isLimiterEnabled_cb _hidl_cb) {
+    return mEffect->getIntegerParam(AGC_PARAM_LIMITER_ENA, _hidl_cb);
+}
+
+Return<Result> AutomaticGainControlEffect::setAllProperties(
+    const IAutomaticGainControlEffect::AllProperties& properties) {
+    t_agc_settings halProperties;
+    propertiesToHal(properties, &halProperties);
+    return mEffect->setParam(AGC_PARAM_PROPERTIES, halProperties);
+}
+
+Return<void> AutomaticGainControlEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
+    t_agc_settings halProperties;
+    Result retval = mEffect->getParam(AGC_PARAM_PROPERTIES, halProperties);
+    AllProperties properties;
+    propertiesFromHal(halProperties, &properties);
+    _hidl_cb(retval, properties);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.h
new file mode 100644
index 0000000..0092621
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.h
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IBassBoostEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct BassBoostEffect : public IBassBoostEffect {
+    explicit BassBoostEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IBassBoostEffect follow.
+    Return<void> isStrengthSupported(isStrengthSupported_cb _hidl_cb) override;
+    Return<Result> setStrength(uint16_t strength) override;
+    Return<void> getStrength(getStrength_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+
+    virtual ~BassBoostEffect();
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.impl.h
new file mode 100644
index 0000000..1fc8d1b
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/BassBoostEffect.impl.h
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <android/log.h>
+#include <system/audio_effects/effect_bassboost.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+BassBoostEffect::BassBoostEffect(effect_handle_t handle) : mEffect(new Effect(handle)) {}
+
+BassBoostEffect::~BassBoostEffect() {}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> BassBoostEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> BassBoostEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> BassBoostEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> BassBoostEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> BassBoostEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> BassBoostEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> BassBoostEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                              setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> BassBoostEffect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> BassBoostEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> BassBoostEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> BassBoostEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> BassBoostEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> BassBoostEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> BassBoostEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> BassBoostEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> BassBoostEffect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> BassBoostEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> BassBoostEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> BassBoostEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> BassBoostEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> BassBoostEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                  const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> BassBoostEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                      uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> BassBoostEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                             const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> BassBoostEffect::getParameter(const hidl_vec<uint8_t>& parameter,
+                                           uint32_t valueMaxSize, getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> BassBoostEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> BassBoostEffect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                                         getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> BassBoostEffect::setCurrentConfigForFeature(uint32_t featureId,
+                                                           const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> BassBoostEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IBassBoostEffect follow.
+Return<void> BassBoostEffect::isStrengthSupported(isStrengthSupported_cb _hidl_cb) {
+    return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH_SUPPORTED, _hidl_cb);
+}
+
+Return<Result> BassBoostEffect::setStrength(uint16_t strength) {
+    return mEffect->setParam(BASSBOOST_PARAM_STRENGTH, strength);
+}
+
+Return<void> BassBoostEffect::getStrength(getStrength_cb _hidl_cb) {
+    return mEffect->getIntegerParam(BASSBOOST_PARAM_STRENGTH, _hidl_cb);
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.h b/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.h
new file mode 100644
index 0000000..3f9317f
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <string>
+
+#include <system/audio_effect.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor;
+
+void effectDescriptorFromHal(const effect_descriptor_t& halDescriptor,
+                             EffectDescriptor* descriptor);
+std::string uuidToString(const effect_uuid_t& halUuid);
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.impl.h
new file mode 100644
index 0000000..44adf4b
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/Conversions.impl.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <memory.h>
+#include <stdio.h>
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::HidlUtils;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+void effectDescriptorFromHal(const effect_descriptor_t& halDescriptor,
+                             EffectDescriptor* descriptor) {
+    HidlUtils::uuidFromHal(halDescriptor.type, &descriptor->type);
+    HidlUtils::uuidFromHal(halDescriptor.uuid, &descriptor->uuid);
+    descriptor->flags = EffectFlags(halDescriptor.flags);
+    descriptor->cpuLoad = halDescriptor.cpuLoad;
+    descriptor->memoryUsage = halDescriptor.memoryUsage;
+    memcpy(descriptor->name.data(), halDescriptor.name, descriptor->name.size());
+    memcpy(descriptor->implementor.data(), halDescriptor.implementor,
+           descriptor->implementor.size());
+}
+
+std::string uuidToString(const effect_uuid_t& halUuid) {
+    char str[64];
+    snprintf(str, sizeof(str), "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", halUuid.timeLow,
+             halUuid.timeMid, halUuid.timeHiAndVersion, halUuid.clockSeq, halUuid.node[0],
+             halUuid.node[1], halUuid.node[2], halUuid.node[3], halUuid.node[4], halUuid.node[5]);
+    return str;
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.h
new file mode 100644
index 0000000..e461ca8
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IDownmixEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct DownmixEffect : public IDownmixEffect {
+    explicit DownmixEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IDownmixEffect follow.
+    Return<Result> setType(IDownmixEffect::Type preset) override;
+    Return<void> getType(getType_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+
+    virtual ~DownmixEffect();
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.impl.h
new file mode 100644
index 0000000..98710f8
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/DownmixEffect.impl.h
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <android/log.h>
+#include <system/audio_effects/effect_downmix.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+DownmixEffect::DownmixEffect(effect_handle_t handle) : mEffect(new Effect(handle)) {}
+
+DownmixEffect::~DownmixEffect() {}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> DownmixEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> DownmixEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> DownmixEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> DownmixEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> DownmixEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> DownmixEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> DownmixEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                            setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> DownmixEffect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> DownmixEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> DownmixEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> DownmixEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> DownmixEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> DownmixEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> DownmixEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> DownmixEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> DownmixEffect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> DownmixEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> DownmixEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> DownmixEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> DownmixEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> DownmixEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> DownmixEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                    uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> DownmixEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                           const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> DownmixEffect::getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                                         getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> DownmixEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> DownmixEffect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                                       getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> DownmixEffect::setCurrentConfigForFeature(uint32_t featureId,
+                                                         const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> DownmixEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IDownmixEffect follow.
+Return<Result> DownmixEffect::setType(IDownmixEffect::Type preset) {
+    return mEffect->setParam(DOWNMIX_PARAM_TYPE, static_cast<downmix_type_t>(preset));
+}
+
+Return<void> DownmixEffect::getType(getType_cb _hidl_cb) {
+    downmix_type_t halPreset = DOWNMIX_TYPE_INVALID;
+    Result retval = mEffect->getParam(DOWNMIX_PARAM_TYPE, halPreset);
+    _hidl_cb(retval, Type(halPreset));
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/Effect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/Effect.h
new file mode 100644
index 0000000..81b0b24
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/Effect.h
@@ -0,0 +1,238 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <atomic>
+#include <memory>
+#include <vector>
+
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <utils/Thread.h>
+
+#include <hardware/audio_effect.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::Uuid;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectFeature;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Effect : public IEffect {
+    typedef MessageQueue<Result, kSynchronizedReadWrite> StatusMQ;
+    using GetParameterSuccessCallback =
+        std::function<void(uint32_t valueSize, const void* valueData)>;
+
+    explicit Effect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Utility methods for extending interfaces.
+    template <typename T>
+    Return<void> getIntegerParam(uint32_t paramId,
+                                 std::function<void(Result retval, T paramValue)> cb) {
+        T value;
+        Result retval = getParameterImpl(sizeof(uint32_t), &paramId, sizeof(T),
+                                         [&](uint32_t valueSize, const void* valueData) {
+                                             if (valueSize > sizeof(T)) valueSize = sizeof(T);
+                                             memcpy(&value, valueData, valueSize);
+                                         });
+        cb(retval, value);
+        return Void();
+    }
+
+    template <typename T>
+    Result getParam(uint32_t paramId, T& paramValue) {
+        return getParameterImpl(sizeof(uint32_t), &paramId, sizeof(T),
+                                [&](uint32_t valueSize, const void* valueData) {
+                                    if (valueSize > sizeof(T)) valueSize = sizeof(T);
+                                    memcpy(&paramValue, valueData, valueSize);
+                                });
+    }
+
+    template <typename T>
+    Result getParam(uint32_t paramId, uint32_t paramArg, T& paramValue) {
+        uint32_t params[2] = {paramId, paramArg};
+        return getParameterImpl(sizeof(params), params, sizeof(T),
+                                [&](uint32_t valueSize, const void* valueData) {
+                                    if (valueSize > sizeof(T)) valueSize = sizeof(T);
+                                    memcpy(&paramValue, valueData, valueSize);
+                                });
+    }
+
+    template <typename T>
+    Result setParam(uint32_t paramId, const T& paramValue) {
+        return setParameterImpl(sizeof(uint32_t), &paramId, sizeof(T), &paramValue);
+    }
+
+    template <typename T>
+    Result setParam(uint32_t paramId, uint32_t paramArg, const T& paramValue) {
+        uint32_t params[2] = {paramId, paramArg};
+        return setParameterImpl(sizeof(params), params, sizeof(T), &paramValue);
+    }
+
+    Result getParameterImpl(uint32_t paramSize, const void* paramData, uint32_t valueSize,
+                            GetParameterSuccessCallback onSuccess) {
+        return getParameterImpl(paramSize, paramData, valueSize, valueSize, onSuccess);
+    }
+    Result getParameterImpl(uint32_t paramSize, const void* paramData, uint32_t requestValueSize,
+                            uint32_t replyValueSize, GetParameterSuccessCallback onSuccess);
+    Result setParameterImpl(uint32_t paramSize, const void* paramData, uint32_t valueSize,
+                            const void* valueData);
+
+   private:
+    friend struct VirtualizerEffect;  // for getParameterImpl
+    friend struct VisualizerEffect;   // to allow executing commands
+
+    using CommandSuccessCallback = std::function<void()>;
+    using GetConfigCallback = std::function<void(Result retval, const EffectConfig& config)>;
+    using GetCurrentConfigSuccessCallback = std::function<void(void* configData)>;
+    using GetSupportedConfigsSuccessCallback =
+        std::function<void(uint32_t supportedConfigs, void* configsData)>;
+
+    static const char* sContextResultOfCommand;
+    static const char* sContextCallToCommand;
+    static const char* sContextCallFunction;
+
+    bool mIsClosed;
+    effect_handle_t mHandle;
+    sp<AudioBufferWrapper> mInBuffer;
+    sp<AudioBufferWrapper> mOutBuffer;
+    std::atomic<audio_buffer_t*> mHalInBufferPtr;
+    std::atomic<audio_buffer_t*> mHalOutBufferPtr;
+    std::unique_ptr<StatusMQ> mStatusMQ;
+    EventFlag* mEfGroup;
+    std::atomic<bool> mStopProcessThread;
+    sp<Thread> mProcessThread;
+
+    virtual ~Effect();
+
+    template <typename T>
+    static size_t alignedSizeIn(size_t s);
+    template <typename T>
+    std::unique_ptr<uint8_t[]> hidlVecToHal(const hidl_vec<T>& vec, uint32_t* halDataSize);
+    static void effectAuxChannelsConfigFromHal(const channel_config_t& halConfig,
+                                               EffectAuxChannelsConfig* config);
+    static void effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config,
+                                             channel_config_t* halConfig);
+    static void effectBufferConfigFromHal(const buffer_config_t& halConfig,
+                                          EffectBufferConfig* config);
+    static void effectBufferConfigToHal(const EffectBufferConfig& config,
+                                        buffer_config_t* halConfig);
+    static void effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config);
+    static void effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig);
+    static void effectOffloadParamToHal(const EffectOffloadParameter& offload,
+                                        effect_offload_param_t* halOffload);
+    static std::vector<uint8_t> parameterToHal(uint32_t paramSize, const void* paramData,
+                                               uint32_t valueSize, const void** valueData);
+
+    Result analyzeCommandStatus(const char* commandName, const char* context, status_t status);
+    Result analyzeStatus(const char* funcName, const char* subFuncName,
+                         const char* contextDescription, status_t status);
+    void getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb);
+    Result getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
+                                GetCurrentConfigSuccessCallback onSuccess);
+    Result getSupportedConfigsImpl(uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+                                   GetSupportedConfigsSuccessCallback onSuccess);
+    Result sendCommand(int commandCode, const char* commandName);
+    Result sendCommand(int commandCode, const char* commandName, uint32_t size, void* data);
+    Result sendCommandReturningData(int commandCode, const char* commandName, uint32_t* replySize,
+                                    void* replyData);
+    Result sendCommandReturningData(int commandCode, const char* commandName, uint32_t size,
+                                    void* data, uint32_t* replySize, void* replyData);
+    Result sendCommandReturningStatus(int commandCode, const char* commandName);
+    Result sendCommandReturningStatus(int commandCode, const char* commandName, uint32_t size,
+                                      void* data);
+    Result sendCommandReturningStatusAndData(int commandCode, const char* commandName,
+                                             uint32_t size, void* data, uint32_t* replySize,
+                                             void* replyData, uint32_t minReplySize,
+                                             CommandSuccessCallback onSuccess);
+    Result setConfigImpl(int commandCode, const char* commandName, const EffectConfig& config,
+                         const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+                         const sp<IEffectBufferProviderCallback>& outputBufferProvider);
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/Effect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/Effect.impl.h
new file mode 100644
index 0000000..d376146
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/Effect.impl.h
@@ -0,0 +1,711 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <memory.h>
+
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+
+#include <android/log.h>
+#include <media/EffectsFactoryApi.h>
+#include <utils/Trace.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioFormat;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::MessageQueueFlagBits;
+
+namespace {
+
+class ProcessThread : public Thread {
+   public:
+    // ProcessThread's lifespan never exceeds Effect's lifespan.
+    ProcessThread(std::atomic<bool>* stop, effect_handle_t effect,
+                  std::atomic<audio_buffer_t*>* inBuffer, std::atomic<audio_buffer_t*>* outBuffer,
+                  Effect::StatusMQ* statusMQ, EventFlag* efGroup)
+        : Thread(false /*canCallJava*/),
+          mStop(stop),
+          mEffect(effect),
+          mHasProcessReverse((*mEffect)->process_reverse != NULL),
+          mInBuffer(inBuffer),
+          mOutBuffer(outBuffer),
+          mStatusMQ(statusMQ),
+          mEfGroup(efGroup) {}
+    virtual ~ProcessThread() {}
+
+   private:
+    std::atomic<bool>* mStop;
+    effect_handle_t mEffect;
+    bool mHasProcessReverse;
+    std::atomic<audio_buffer_t*>* mInBuffer;
+    std::atomic<audio_buffer_t*>* mOutBuffer;
+    Effect::StatusMQ* mStatusMQ;
+    EventFlag* mEfGroup;
+
+    bool threadLoop() override;
+};
+
+bool ProcessThread::threadLoop() {
+    // This implementation doesn't return control back to the Thread until it decides to stop,
+    // as the Thread uses mutexes, and this can lead to priority inversion.
+    while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+        uint32_t efState = 0;
+        mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL), &efState);
+        if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_ALL)) ||
+            (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT))) {
+            continue;  // Nothing to do or time to quit.
+        }
+        Result retval = Result::OK;
+        if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE) &&
+            !mHasProcessReverse) {
+            retval = Result::NOT_SUPPORTED;
+        }
+
+        if (retval == Result::OK) {
+            // affects both buffer pointers and their contents.
+            std::atomic_thread_fence(std::memory_order_acquire);
+            int32_t processResult;
+            audio_buffer_t* inBuffer =
+                std::atomic_load_explicit(mInBuffer, std::memory_order_relaxed);
+            audio_buffer_t* outBuffer =
+                std::atomic_load_explicit(mOutBuffer, std::memory_order_relaxed);
+            if (inBuffer != nullptr && outBuffer != nullptr) {
+                if (efState & static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS)) {
+                    processResult = (*mEffect)->process(mEffect, inBuffer, outBuffer);
+                } else {
+                    processResult = (*mEffect)->process_reverse(mEffect, inBuffer, outBuffer);
+                }
+                std::atomic_thread_fence(std::memory_order_release);
+            } else {
+                ALOGE("processing buffers were not set before calling 'process'");
+                processResult = -ENODEV;
+            }
+            switch (processResult) {
+                case 0:
+                    retval = Result::OK;
+                    break;
+                case -ENODATA:
+                    retval = Result::INVALID_STATE;
+                    break;
+                case -EINVAL:
+                    retval = Result::INVALID_ARGUMENTS;
+                    break;
+                default:
+                    retval = Result::NOT_INITIALIZED;
+            }
+        }
+        if (!mStatusMQ->write(&retval)) {
+            ALOGW("status message queue write failed");
+        }
+        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING));
+    }
+
+    return false;
+}
+
+}  // namespace
+
+// static
+const char* Effect::sContextResultOfCommand = "returned status";
+const char* Effect::sContextCallToCommand = "error";
+const char* Effect::sContextCallFunction = sContextCallToCommand;
+
+Effect::Effect(effect_handle_t handle)
+    : mIsClosed(false), mHandle(handle), mEfGroup(nullptr), mStopProcessThread(false) {}
+
+Effect::~Effect() {
+    ATRACE_CALL();
+    close();
+    if (mProcessThread.get()) {
+        ATRACE_NAME("mProcessThread->join");
+        status_t status = mProcessThread->join();
+        ALOGE_IF(status, "processing thread exit error: %s", strerror(-status));
+    }
+    if (mEfGroup) {
+        status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+        ALOGE_IF(status, "processing MQ event flag deletion error: %s", strerror(-status));
+    }
+    mInBuffer.clear();
+    mOutBuffer.clear();
+    int status = EffectRelease(mHandle);
+    ALOGW_IF(status, "Error releasing effect %p: %s", mHandle, strerror(-status));
+    EffectMap::getInstance().remove(mHandle);
+    mHandle = 0;
+}
+
+// static
+template <typename T>
+size_t Effect::alignedSizeIn(size_t s) {
+    return (s + sizeof(T) - 1) / sizeof(T);
+}
+
+// static
+template <typename T>
+std::unique_ptr<uint8_t[]> Effect::hidlVecToHal(const hidl_vec<T>& vec, uint32_t* halDataSize) {
+    // Due to bugs in HAL, they may attempt to write into the provided
+    // input buffer. The original binder buffer is r/o, thus it is needed
+    // to create a r/w version.
+    *halDataSize = vec.size() * sizeof(T);
+    std::unique_ptr<uint8_t[]> halData(new uint8_t[*halDataSize]);
+    memcpy(&halData[0], &vec[0], *halDataSize);
+    return halData;
+}
+
+// static
+void Effect::effectAuxChannelsConfigFromHal(const channel_config_t& halConfig,
+                                            EffectAuxChannelsConfig* config) {
+    config->mainChannels = AudioChannelMask(halConfig.main_channels);
+    config->auxChannels = AudioChannelMask(halConfig.aux_channels);
+}
+
+// static
+void Effect::effectAuxChannelsConfigToHal(const EffectAuxChannelsConfig& config,
+                                          channel_config_t* halConfig) {
+    halConfig->main_channels = static_cast<audio_channel_mask_t>(config.mainChannels);
+    halConfig->aux_channels = static_cast<audio_channel_mask_t>(config.auxChannels);
+}
+
+// static
+void Effect::effectBufferConfigFromHal(const buffer_config_t& halConfig,
+                                       EffectBufferConfig* config) {
+    config->buffer.id = 0;
+    config->buffer.frameCount = 0;
+    config->samplingRateHz = halConfig.samplingRate;
+    config->channels = AudioChannelMask(halConfig.channels);
+    config->format = AudioFormat(halConfig.format);
+    config->accessMode = EffectBufferAccess(halConfig.accessMode);
+    config->mask = EffectConfigParameters(halConfig.mask);
+}
+
+// static
+void Effect::effectBufferConfigToHal(const EffectBufferConfig& config, buffer_config_t* halConfig) {
+    // Note: setting the buffers directly is considered obsolete. They need to be set
+    // using 'setProcessBuffers'.
+    halConfig->buffer.frameCount = 0;
+    halConfig->buffer.raw = NULL;
+    halConfig->samplingRate = config.samplingRateHz;
+    halConfig->channels = static_cast<uint32_t>(config.channels);
+    // Note: The framework code does not use BP.
+    halConfig->bufferProvider.cookie = NULL;
+    halConfig->bufferProvider.getBuffer = NULL;
+    halConfig->bufferProvider.releaseBuffer = NULL;
+    halConfig->format = static_cast<uint8_t>(config.format);
+    halConfig->accessMode = static_cast<uint8_t>(config.accessMode);
+    halConfig->mask = static_cast<uint8_t>(config.mask);
+}
+
+// static
+void Effect::effectConfigFromHal(const effect_config_t& halConfig, EffectConfig* config) {
+    effectBufferConfigFromHal(halConfig.inputCfg, &config->inputCfg);
+    effectBufferConfigFromHal(halConfig.outputCfg, &config->outputCfg);
+}
+
+// static
+void Effect::effectConfigToHal(const EffectConfig& config, effect_config_t* halConfig) {
+    effectBufferConfigToHal(config.inputCfg, &halConfig->inputCfg);
+    effectBufferConfigToHal(config.outputCfg, &halConfig->outputCfg);
+}
+
+// static
+void Effect::effectOffloadParamToHal(const EffectOffloadParameter& offload,
+                                     effect_offload_param_t* halOffload) {
+    halOffload->isOffload = offload.isOffload;
+    halOffload->ioHandle = offload.ioHandle;
+}
+
+// static
+std::vector<uint8_t> Effect::parameterToHal(uint32_t paramSize, const void* paramData,
+                                            uint32_t valueSize, const void** valueData) {
+    size_t valueOffsetFromData = alignedSizeIn<uint32_t>(paramSize) * sizeof(uint32_t);
+    size_t halParamBufferSize = sizeof(effect_param_t) + valueOffsetFromData + valueSize;
+    std::vector<uint8_t> halParamBuffer(halParamBufferSize, 0);
+    effect_param_t* halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
+    halParam->psize = paramSize;
+    halParam->vsize = valueSize;
+    memcpy(halParam->data, paramData, paramSize);
+    if (valueData) {
+        if (*valueData) {
+            // Value data is provided.
+            memcpy(halParam->data + valueOffsetFromData, *valueData, valueSize);
+        } else {
+            // The caller needs the pointer to the value data location.
+            *valueData = halParam->data + valueOffsetFromData;
+        }
+    }
+    return halParamBuffer;
+}
+
+Result Effect::analyzeCommandStatus(const char* commandName, const char* context, status_t status) {
+    return analyzeStatus("command", commandName, context, status);
+}
+
+Result Effect::analyzeStatus(const char* funcName, const char* subFuncName,
+                             const char* contextDescription, status_t status) {
+    if (status != OK) {
+        ALOGW("Effect %p %s %s %s: %s", mHandle, funcName, subFuncName, contextDescription,
+              strerror(-status));
+    }
+    switch (status) {
+        case OK:
+            return Result::OK;
+        case -EINVAL:
+            return Result::INVALID_ARGUMENTS;
+        case -ENODATA:
+            return Result::INVALID_STATE;
+        case -ENODEV:
+            return Result::NOT_INITIALIZED;
+        case -ENOMEM:
+            return Result::RESULT_TOO_BIG;
+        case -ENOSYS:
+            return Result::NOT_SUPPORTED;
+        default:
+            return Result::INVALID_STATE;
+    }
+}
+
+void Effect::getConfigImpl(int commandCode, const char* commandName, GetConfigCallback cb) {
+    uint32_t halResultSize = sizeof(effect_config_t);
+    effect_config_t halConfig{};
+    status_t status =
+        (*mHandle)->command(mHandle, commandCode, 0, NULL, &halResultSize, &halConfig);
+    EffectConfig config;
+    if (status == OK) {
+        effectConfigFromHal(halConfig, &config);
+    }
+    cb(analyzeCommandStatus(commandName, sContextCallToCommand, status), config);
+}
+
+Result Effect::getCurrentConfigImpl(uint32_t featureId, uint32_t configSize,
+                                    GetCurrentConfigSuccessCallback onSuccess) {
+    uint32_t halCmd = featureId;
+    uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configSize)];
+    memset(halResult, 0, sizeof(halResult));
+    uint32_t halResultSize = 0;
+    return sendCommandReturningStatusAndData(EFFECT_CMD_GET_FEATURE_CONFIG, "GET_FEATURE_CONFIG",
+                                             sizeof(uint32_t), &halCmd, &halResultSize, halResult,
+                                             sizeof(uint32_t), [&] { onSuccess(&halResult[1]); });
+}
+
+Result Effect::getParameterImpl(uint32_t paramSize, const void* paramData,
+                                uint32_t requestValueSize, uint32_t replyValueSize,
+                                GetParameterSuccessCallback onSuccess) {
+    // As it is unknown what method HAL uses for copying the provided parameter data,
+    // it is safer to make sure that input and output buffers do not overlap.
+    std::vector<uint8_t> halCmdBuffer =
+        parameterToHal(paramSize, paramData, requestValueSize, nullptr);
+    const void* valueData = nullptr;
+    std::vector<uint8_t> halParamBuffer =
+        parameterToHal(paramSize, paramData, replyValueSize, &valueData);
+    uint32_t halParamBufferSize = halParamBuffer.size();
+
+    return sendCommandReturningStatusAndData(
+        EFFECT_CMD_GET_PARAM, "GET_PARAM", halCmdBuffer.size(), &halCmdBuffer[0],
+        &halParamBufferSize, &halParamBuffer[0], sizeof(effect_param_t), [&] {
+            effect_param_t* halParam = reinterpret_cast<effect_param_t*>(&halParamBuffer[0]);
+            onSuccess(halParam->vsize, valueData);
+        });
+}
+
+Result Effect::getSupportedConfigsImpl(uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+                                       GetSupportedConfigsSuccessCallback onSuccess) {
+    uint32_t halCmd[2] = {featureId, maxConfigs};
+    uint32_t halResultSize = 2 * sizeof(uint32_t) + maxConfigs * sizeof(configSize);
+    uint8_t halResult[halResultSize];
+    memset(&halResult[0], 0, halResultSize);
+    return sendCommandReturningStatusAndData(
+        EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS, "GET_FEATURE_SUPPORTED_CONFIGS", sizeof(halCmd),
+        halCmd, &halResultSize, &halResult[0], 2 * sizeof(uint32_t), [&] {
+            uint32_t* halResult32 = reinterpret_cast<uint32_t*>(&halResult[0]);
+            uint32_t supportedConfigs = *(++halResult32);  // skip status field
+            if (supportedConfigs > maxConfigs) supportedConfigs = maxConfigs;
+            onSuccess(supportedConfigs, ++halResult32);
+        });
+}
+
+Return<void> Effect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    status_t status;
+    // Create message queue.
+    if (mStatusMQ) {
+        ALOGE("the client attempts to call prepareForProcessing_cb twice");
+        _hidl_cb(Result::INVALID_STATE, StatusMQ::Descriptor());
+        return Void();
+    }
+    std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1, true /*EventFlag*/));
+    if (!tempStatusMQ->isValid()) {
+        ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+        _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
+        return Void();
+    }
+    status = EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
+    if (status != OK || !mEfGroup) {
+        ALOGE("failed creating event flag for status MQ: %s", strerror(-status));
+        _hidl_cb(Result::INVALID_ARGUMENTS, StatusMQ::Descriptor());
+        return Void();
+    }
+
+    // Create and launch the thread.
+    mProcessThread = new ProcessThread(&mStopProcessThread, mHandle, &mHalInBufferPtr,
+                                       &mHalOutBufferPtr, tempStatusMQ.get(), mEfGroup);
+    status = mProcessThread->run("effect", PRIORITY_URGENT_AUDIO);
+    if (status != OK) {
+        ALOGW("failed to start effect processing thread: %s", strerror(-status));
+        _hidl_cb(Result::INVALID_ARGUMENTS, MQDescriptorSync<Result>());
+        return Void();
+    }
+
+    mStatusMQ = std::move(tempStatusMQ);
+    _hidl_cb(Result::OK, *mStatusMQ->getDesc());
+    return Void();
+}
+
+Return<Result> Effect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                         const AudioBuffer& outBuffer) {
+    AudioBufferManager& manager = AudioBufferManager::getInstance();
+    sp<AudioBufferWrapper> tempInBuffer, tempOutBuffer;
+    if (!manager.wrap(inBuffer, &tempInBuffer)) {
+        ALOGE("Could not map memory of the input buffer");
+        return Result::INVALID_ARGUMENTS;
+    }
+    if (!manager.wrap(outBuffer, &tempOutBuffer)) {
+        ALOGE("Could not map memory of the output buffer");
+        return Result::INVALID_ARGUMENTS;
+    }
+    mInBuffer = tempInBuffer;
+    mOutBuffer = tempOutBuffer;
+    // The processing thread only reads these pointers after waking up by an event flag,
+    // so it's OK to update the pair non-atomically.
+    mHalInBufferPtr.store(mInBuffer->getHalBuffer(), std::memory_order_release);
+    mHalOutBufferPtr.store(mOutBuffer->getHalBuffer(), std::memory_order_release);
+    return Result::OK;
+}
+
+Result Effect::sendCommand(int commandCode, const char* commandName) {
+    return sendCommand(commandCode, commandName, 0, NULL);
+}
+
+Result Effect::sendCommand(int commandCode, const char* commandName, uint32_t size, void* data) {
+    status_t status = (*mHandle)->command(mHandle, commandCode, size, data, 0, NULL);
+    return analyzeCommandStatus(commandName, sContextCallToCommand, status);
+}
+
+Result Effect::sendCommandReturningData(int commandCode, const char* commandName,
+                                        uint32_t* replySize, void* replyData) {
+    return sendCommandReturningData(commandCode, commandName, 0, NULL, replySize, replyData);
+}
+
+Result Effect::sendCommandReturningData(int commandCode, const char* commandName, uint32_t size,
+                                        void* data, uint32_t* replySize, void* replyData) {
+    uint32_t expectedReplySize = *replySize;
+    status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
+    if (status == OK && *replySize != expectedReplySize) {
+        status = -ENODATA;
+    }
+    return analyzeCommandStatus(commandName, sContextCallToCommand, status);
+}
+
+Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName) {
+    return sendCommandReturningStatus(commandCode, commandName, 0, NULL);
+}
+
+Result Effect::sendCommandReturningStatus(int commandCode, const char* commandName, uint32_t size,
+                                          void* data) {
+    uint32_t replyCmdStatus;
+    uint32_t replySize = sizeof(uint32_t);
+    return sendCommandReturningStatusAndData(commandCode, commandName, size, data, &replySize,
+                                             &replyCmdStatus, replySize, [] {});
+}
+
+Result Effect::sendCommandReturningStatusAndData(int commandCode, const char* commandName,
+                                                 uint32_t size, void* data, uint32_t* replySize,
+                                                 void* replyData, uint32_t minReplySize,
+                                                 CommandSuccessCallback onSuccess) {
+    status_t status = (*mHandle)->command(mHandle, commandCode, size, data, replySize, replyData);
+    Result retval;
+    if (status == OK && minReplySize >= sizeof(uint32_t) && *replySize >= minReplySize) {
+        uint32_t commandStatus = *reinterpret_cast<uint32_t*>(replyData);
+        retval = analyzeCommandStatus(commandName, sContextResultOfCommand, commandStatus);
+        if (commandStatus == OK) {
+            onSuccess();
+        }
+    } else {
+        retval = analyzeCommandStatus(commandName, sContextCallToCommand, status);
+    }
+    return retval;
+}
+
+Result Effect::setConfigImpl(int commandCode, const char* commandName, const EffectConfig& config,
+                             const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+                             const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    effect_config_t halConfig;
+    effectConfigToHal(config, &halConfig);
+    if (inputBufferProvider != 0) {
+        LOG_FATAL("Using input buffer provider is not supported");
+    }
+    if (outputBufferProvider != 0) {
+        LOG_FATAL("Using output buffer provider is not supported");
+    }
+    return sendCommandReturningStatus(commandCode, commandName, sizeof(effect_config_t),
+                                      &halConfig);
+}
+
+Result Effect::setParameterImpl(uint32_t paramSize, const void* paramData, uint32_t valueSize,
+                                const void* valueData) {
+    std::vector<uint8_t> halParamBuffer =
+        parameterToHal(paramSize, paramData, valueSize, &valueData);
+    return sendCommandReturningStatus(EFFECT_CMD_SET_PARAM, "SET_PARAM", halParamBuffer.size(),
+                                      &halParamBuffer[0]);
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> Effect::init() {
+    return sendCommandReturningStatus(EFFECT_CMD_INIT, "INIT");
+}
+
+Return<Result> Effect::setConfig(const EffectConfig& config,
+                                 const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+                                 const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return setConfigImpl(EFFECT_CMD_SET_CONFIG, "SET_CONFIG", config, inputBufferProvider,
+                         outputBufferProvider);
+}
+
+Return<Result> Effect::reset() {
+    return sendCommand(EFFECT_CMD_RESET, "RESET");
+}
+
+Return<Result> Effect::enable() {
+    return sendCommandReturningStatus(EFFECT_CMD_ENABLE, "ENABLE");
+}
+
+Return<Result> Effect::disable() {
+    return sendCommandReturningStatus(EFFECT_CMD_DISABLE, "DISABLE");
+}
+
+Return<Result> Effect::setDevice(AudioDevice device) {
+    uint32_t halDevice = static_cast<uint32_t>(device);
+    return sendCommand(EFFECT_CMD_SET_DEVICE, "SET_DEVICE", sizeof(uint32_t), &halDevice);
+}
+
+Return<void> Effect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                     setAndGetVolume_cb _hidl_cb) {
+    uint32_t halDataSize;
+    std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
+    uint32_t halResultSize = halDataSize;
+    uint32_t halResult[volumes.size()];
+    Result retval = sendCommandReturningData(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize,
+                                             &halData[0], &halResultSize, halResult);
+    hidl_vec<uint32_t> result;
+    if (retval == Result::OK) {
+        result.setToExternal(&halResult[0], halResultSize);
+    }
+    _hidl_cb(retval, result);
+    return Void();
+}
+
+Return<Result> Effect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+    uint32_t halDataSize;
+    std::unique_ptr<uint8_t[]> halData = hidlVecToHal(volumes, &halDataSize);
+    return sendCommand(EFFECT_CMD_SET_VOLUME, "SET_VOLUME", halDataSize, &halData[0]);
+}
+
+Return<Result> Effect::setAudioMode(AudioMode mode) {
+    uint32_t halMode = static_cast<uint32_t>(mode);
+    return sendCommand(EFFECT_CMD_SET_AUDIO_MODE, "SET_AUDIO_MODE", sizeof(uint32_t), &halMode);
+}
+
+Return<Result> Effect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return setConfigImpl(EFFECT_CMD_SET_CONFIG_REVERSE, "SET_CONFIG_REVERSE", config,
+                         inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> Effect::setInputDevice(AudioDevice device) {
+    uint32_t halDevice = static_cast<uint32_t>(device);
+    return sendCommand(EFFECT_CMD_SET_INPUT_DEVICE, "SET_INPUT_DEVICE", sizeof(uint32_t),
+                       &halDevice);
+}
+
+Return<void> Effect::getConfig(getConfig_cb _hidl_cb) {
+    getConfigImpl(EFFECT_CMD_GET_CONFIG, "GET_CONFIG", _hidl_cb);
+    return Void();
+}
+
+Return<void> Effect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    getConfigImpl(EFFECT_CMD_GET_CONFIG_REVERSE, "GET_CONFIG_REVERSE", _hidl_cb);
+    return Void();
+}
+
+Return<void> Effect::getSupportedAuxChannelsConfigs(uint32_t maxConfigs,
+                                                    getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    hidl_vec<EffectAuxChannelsConfig> result;
+    Result retval = getSupportedConfigsImpl(
+        EFFECT_FEATURE_AUX_CHANNELS, maxConfigs, sizeof(channel_config_t),
+        [&](uint32_t supportedConfigs, void* configsData) {
+            result.resize(supportedConfigs);
+            channel_config_t* config = reinterpret_cast<channel_config_t*>(configsData);
+            for (size_t i = 0; i < result.size(); ++i) {
+                effectAuxChannelsConfigFromHal(*config++, &result[i]);
+            }
+        });
+    _hidl_cb(retval, result);
+    return Void();
+}
+
+Return<void> Effect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    uint32_t halResult[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
+    memset(halResult, 0, sizeof(halResult));
+    EffectAuxChannelsConfig result;
+    Result retval = getCurrentConfigImpl(
+        EFFECT_FEATURE_AUX_CHANNELS, sizeof(channel_config_t), [&](void* configData) {
+            effectAuxChannelsConfigFromHal(*reinterpret_cast<channel_config_t*>(configData),
+                                           &result);
+        });
+    _hidl_cb(retval, result);
+    return Void();
+}
+
+Return<Result> Effect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+    uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + sizeof(channel_config_t))];
+    halCmd[0] = EFFECT_FEATURE_AUX_CHANNELS;
+    effectAuxChannelsConfigToHal(config, reinterpret_cast<channel_config_t*>(&halCmd[1]));
+    return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG,
+                                      "SET_FEATURE_CONFIG AUX_CHANNELS", sizeof(halCmd), halCmd);
+}
+
+Return<Result> Effect::setAudioSource(AudioSource source) {
+    uint32_t halSource = static_cast<uint32_t>(source);
+    return sendCommand(EFFECT_CMD_SET_AUDIO_SOURCE, "SET_AUDIO_SOURCE", sizeof(uint32_t),
+                       &halSource);
+}
+
+Return<Result> Effect::offload(const EffectOffloadParameter& param) {
+    effect_offload_param_t halParam;
+    effectOffloadParamToHal(param, &halParam);
+    return sendCommandReturningStatus(EFFECT_CMD_OFFLOAD, "OFFLOAD", sizeof(effect_offload_param_t),
+                                      &halParam);
+}
+
+Return<void> Effect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    effect_descriptor_t halDescriptor;
+    memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
+    status_t status = (*mHandle)->get_descriptor(mHandle, &halDescriptor);
+    EffectDescriptor descriptor;
+    if (status == OK) {
+        effectDescriptorFromHal(halDescriptor, &descriptor);
+    }
+    _hidl_cb(analyzeStatus("get_descriptor", "", sContextCallFunction, status), descriptor);
+    return Void();
+}
+
+Return<void> Effect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                             uint32_t resultMaxSize, command_cb _hidl_cb) {
+    uint32_t halDataSize;
+    std::unique_ptr<uint8_t[]> halData = hidlVecToHal(data, &halDataSize);
+    uint32_t halResultSize = resultMaxSize;
+    std::unique_ptr<uint8_t[]> halResult(new uint8_t[halResultSize]);
+    memset(&halResult[0], 0, halResultSize);
+
+    void* dataPtr = halDataSize > 0 ? &halData[0] : NULL;
+    void* resultPtr = halResultSize > 0 ? &halResult[0] : NULL;
+    status_t status =
+        (*mHandle)->command(mHandle, commandId, halDataSize, dataPtr, &halResultSize, resultPtr);
+    hidl_vec<uint8_t> result;
+    if (status == OK && resultPtr != NULL) {
+        result.setToExternal(&halResult[0], halResultSize);
+    }
+    _hidl_cb(status, result);
+    return Void();
+}
+
+Return<Result> Effect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                    const hidl_vec<uint8_t>& value) {
+    return setParameterImpl(parameter.size(), &parameter[0], value.size(), &value[0]);
+}
+
+Return<void> Effect::getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                                  getParameter_cb _hidl_cb) {
+    hidl_vec<uint8_t> value;
+    Result retval = getParameterImpl(
+        parameter.size(), &parameter[0], valueMaxSize,
+        [&](uint32_t valueSize, const void* valueData) {
+            value.setToExternal(reinterpret_cast<uint8_t*>(const_cast<void*>(valueData)),
+                                valueSize);
+        });
+    _hidl_cb(retval, value);
+    return Void();
+}
+
+Return<void> Effect::getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                                   uint32_t configSize,
+                                                   getSupportedConfigsForFeature_cb _hidl_cb) {
+    uint32_t configCount = 0;
+    hidl_vec<uint8_t> result;
+    Result retval = getSupportedConfigsImpl(featureId, maxConfigs, configSize,
+                                            [&](uint32_t supportedConfigs, void* configsData) {
+                                                configCount = supportedConfigs;
+                                                result.resize(configCount * configSize);
+                                                memcpy(&result[0], configsData, result.size());
+                                            });
+    _hidl_cb(retval, configCount, result);
+    return Void();
+}
+
+Return<void> Effect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                                getCurrentConfigForFeature_cb _hidl_cb) {
+    hidl_vec<uint8_t> result;
+    Result retval = getCurrentConfigImpl(featureId, configSize, [&](void* configData) {
+        result.resize(configSize);
+        memcpy(&result[0], configData, result.size());
+    });
+    _hidl_cb(retval, result);
+    return Void();
+}
+
+Return<Result> Effect::setCurrentConfigForFeature(uint32_t featureId,
+                                                  const hidl_vec<uint8_t>& configData) {
+    uint32_t halCmd[alignedSizeIn<uint32_t>(sizeof(uint32_t) + configData.size())];
+    memset(halCmd, 0, sizeof(halCmd));
+    halCmd[0] = featureId;
+    memcpy(&halCmd[1], &configData[0], configData.size());
+    return sendCommandReturningStatus(EFFECT_CMD_SET_FEATURE_CONFIG, "SET_FEATURE_CONFIG",
+                                      sizeof(halCmd), halCmd);
+}
+
+Return<Result> Effect::close() {
+    if (mIsClosed) return Result::INVALID_STATE;
+    mIsClosed = true;
+    if (mProcessThread.get()) {
+        mStopProcessThread.store(true, std::memory_order_release);
+    }
+    if (mEfGroup) {
+        mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_QUIT));
+    }
+    return Result::OK;
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.h b/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.h
new file mode 100644
index 0000000..e586abb
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <hardware/audio_effect.h>
+#include <system/audio_effect.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::Uuid;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectsFactory;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct EffectsFactory : public IEffectsFactory {
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectsFactory follow.
+    Return<void> getAllDescriptors(getAllDescriptors_cb _hidl_cb) override;
+    Return<void> getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) override;
+    Return<void> createEffect(const Uuid& uid, int32_t session, int32_t ioHandle,
+                              createEffect_cb _hidl_cb) override;
+    Return<void> debugDump(const hidl_handle& fd) override;
+
+   private:
+    static sp<IEffect> dispatchEffectInstanceCreation(const effect_descriptor_t& halDescriptor,
+                                                      effect_handle_t handle);
+};
+
+extern "C" IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name);
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
new file mode 100644
index 0000000..b2a36a9
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <android/log.h>
+#include <media/EffectsFactoryApi.h>
+#include <system/audio_effects/effect_aec.h>
+#include <system/audio_effects/effect_agc.h>
+#include <system/audio_effects/effect_bassboost.h>
+#include <system/audio_effects/effect_downmix.h>
+#include <system/audio_effects/effect_environmentalreverb.h>
+#include <system/audio_effects/effect_equalizer.h>
+#include <system/audio_effects/effect_loudnessenhancer.h>
+#include <system/audio_effects/effect_ns.h>
+#include <system/audio_effects/effect_presetreverb.h>
+#include <system/audio_effects/effect_virtualizer.h>
+#include <system/audio_effects/effect_visualizer.h>
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::HidlUtils;
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+// static
+sp<IEffect> EffectsFactory::dispatchEffectInstanceCreation(const effect_descriptor_t& halDescriptor,
+                                                           effect_handle_t handle) {
+    const effect_uuid_t* halUuid = &halDescriptor.type;
+    if (memcmp(halUuid, FX_IID_AEC, sizeof(effect_uuid_t)) == 0) {
+        return new AcousticEchoCancelerEffect(handle);
+    } else if (memcmp(halUuid, FX_IID_AGC, sizeof(effect_uuid_t)) == 0) {
+        return new AutomaticGainControlEffect(handle);
+    } else if (memcmp(halUuid, SL_IID_BASSBOOST, sizeof(effect_uuid_t)) == 0) {
+        return new BassBoostEffect(handle);
+    } else if (memcmp(halUuid, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
+        return new DownmixEffect(handle);
+    } else if (memcmp(halUuid, SL_IID_ENVIRONMENTALREVERB, sizeof(effect_uuid_t)) == 0) {
+        return new EnvironmentalReverbEffect(handle);
+    } else if (memcmp(halUuid, SL_IID_EQUALIZER, sizeof(effect_uuid_t)) == 0) {
+        return new EqualizerEffect(handle);
+    } else if (memcmp(halUuid, FX_IID_LOUDNESS_ENHANCER, sizeof(effect_uuid_t)) == 0) {
+        return new LoudnessEnhancerEffect(handle);
+    } else if (memcmp(halUuid, FX_IID_NS, sizeof(effect_uuid_t)) == 0) {
+        return new NoiseSuppressionEffect(handle);
+    } else if (memcmp(halUuid, SL_IID_PRESETREVERB, sizeof(effect_uuid_t)) == 0) {
+        return new PresetReverbEffect(handle);
+    } else if (memcmp(halUuid, SL_IID_VIRTUALIZER, sizeof(effect_uuid_t)) == 0) {
+        return new VirtualizerEffect(handle);
+    } else if (memcmp(halUuid, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) {
+        return new VisualizerEffect(handle);
+    }
+    return new Effect(handle);
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectsFactory follow.
+Return<void> EffectsFactory::getAllDescriptors(getAllDescriptors_cb _hidl_cb) {
+    Result retval(Result::OK);
+    hidl_vec<EffectDescriptor> result;
+    uint32_t numEffects;
+    status_t status;
+
+restart:
+    numEffects = 0;
+    status = EffectQueryNumberEffects(&numEffects);
+    if (status != OK) {
+        retval = Result::NOT_INITIALIZED;
+        ALOGE("Error querying number of effects: %s", strerror(-status));
+        goto exit;
+    }
+    result.resize(numEffects);
+    for (uint32_t i = 0; i < numEffects; ++i) {
+        effect_descriptor_t halDescriptor;
+        status = EffectQueryEffect(i, &halDescriptor);
+        if (status == OK) {
+            effectDescriptorFromHal(halDescriptor, &result[i]);
+        } else {
+            ALOGE("Error querying effect at position %d / %d: %s", i, numEffects,
+                  strerror(-status));
+            switch (status) {
+                case -ENOSYS: {
+                    // Effect list has changed.
+                    goto restart;
+                }
+                case -ENOENT: {
+                    // No more effects available.
+                    result.resize(i);
+                }
+                default: {
+                    result.resize(0);
+                    retval = Result::NOT_INITIALIZED;
+                }
+            }
+            break;
+        }
+    }
+
+exit:
+    _hidl_cb(retval, result);
+    return Void();
+}
+
+Return<void> EffectsFactory::getDescriptor(const Uuid& uid, getDescriptor_cb _hidl_cb) {
+    effect_uuid_t halUuid;
+    HidlUtils::uuidToHal(uid, &halUuid);
+    effect_descriptor_t halDescriptor;
+    status_t status = EffectGetDescriptor(&halUuid, &halDescriptor);
+    EffectDescriptor descriptor;
+    effectDescriptorFromHal(halDescriptor, &descriptor);
+    Result retval(Result::OK);
+    if (status != OK) {
+        ALOGE("Error querying effect descriptor for %s: %s", uuidToString(halUuid).c_str(),
+              strerror(-status));
+        if (status == -ENOENT) {
+            retval = Result::INVALID_ARGUMENTS;
+        } else {
+            retval = Result::NOT_INITIALIZED;
+        }
+    }
+    _hidl_cb(retval, descriptor);
+    return Void();
+}
+
+Return<void> EffectsFactory::createEffect(const Uuid& uid, int32_t session, int32_t ioHandle,
+                                          createEffect_cb _hidl_cb) {
+    effect_uuid_t halUuid;
+    HidlUtils::uuidToHal(uid, &halUuid);
+    effect_handle_t handle;
+    Result retval(Result::OK);
+    status_t status = EffectCreate(&halUuid, session, ioHandle, &handle);
+    sp<IEffect> effect;
+    uint64_t effectId = EffectMap::INVALID_ID;
+    if (status == OK) {
+        effect_descriptor_t halDescriptor;
+        memset(&halDescriptor, 0, sizeof(effect_descriptor_t));
+        status = (*handle)->get_descriptor(handle, &halDescriptor);
+        if (status == OK) {
+            effect = dispatchEffectInstanceCreation(halDescriptor, handle);
+            effectId = EffectMap::getInstance().add(handle);
+        } else {
+            ALOGE("Error querying effect descriptor for %s: %s", uuidToString(halUuid).c_str(),
+                  strerror(-status));
+            EffectRelease(handle);
+        }
+    }
+    if (status != OK) {
+        ALOGE("Error creating effect %s: %s", uuidToString(halUuid).c_str(), strerror(-status));
+        if (status == -ENOENT) {
+            retval = Result::INVALID_ARGUMENTS;
+        } else {
+            retval = Result::NOT_INITIALIZED;
+        }
+    }
+    _hidl_cb(retval, effect, effectId);
+    return Void();
+}
+
+Return<void> EffectsFactory::debugDump(const hidl_handle& fd) {
+    if (fd.getNativeHandle() != nullptr && fd->numFds == 1) {
+        EffectDumpEffects(fd->data[0]);
+    }
+    return Void();
+}
+
+IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* /* name */) {
+    return new EffectsFactory();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.h
new file mode 100644
index 0000000..8351e55
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <system/audio_effects/effect_environmentalreverb.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEnvironmentalReverbEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct EnvironmentalReverbEffect : public IEnvironmentalReverbEffect {
+    explicit EnvironmentalReverbEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from
+    // ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEnvironmentalReverbEffect follow.
+    Return<Result> setBypass(bool bypass) override;
+    Return<void> getBypass(getBypass_cb _hidl_cb) override;
+    Return<Result> setRoomLevel(int16_t roomLevel) override;
+    Return<void> getRoomLevel(getRoomLevel_cb _hidl_cb) override;
+    Return<Result> setRoomHfLevel(int16_t roomHfLevel) override;
+    Return<void> getRoomHfLevel(getRoomHfLevel_cb _hidl_cb) override;
+    Return<Result> setDecayTime(uint32_t decayTime) override;
+    Return<void> getDecayTime(getDecayTime_cb _hidl_cb) override;
+    Return<Result> setDecayHfRatio(int16_t decayHfRatio) override;
+    Return<void> getDecayHfRatio(getDecayHfRatio_cb _hidl_cb) override;
+    Return<Result> setReflectionsLevel(int16_t reflectionsLevel) override;
+    Return<void> getReflectionsLevel(getReflectionsLevel_cb _hidl_cb) override;
+    Return<Result> setReflectionsDelay(uint32_t reflectionsDelay) override;
+    Return<void> getReflectionsDelay(getReflectionsDelay_cb _hidl_cb) override;
+    Return<Result> setReverbLevel(int16_t reverbLevel) override;
+    Return<void> getReverbLevel(getReverbLevel_cb _hidl_cb) override;
+    Return<Result> setReverbDelay(uint32_t reverbDelay) override;
+    Return<void> getReverbDelay(getReverbDelay_cb _hidl_cb) override;
+    Return<Result> setDiffusion(int16_t diffusion) override;
+    Return<void> getDiffusion(getDiffusion_cb _hidl_cb) override;
+    Return<Result> setDensity(int16_t density) override;
+    Return<void> getDensity(getDensity_cb _hidl_cb) override;
+    Return<Result> setAllProperties(
+        const IEnvironmentalReverbEffect::AllProperties& properties) override;
+    Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+
+    virtual ~EnvironmentalReverbEffect();
+
+    void propertiesFromHal(const t_reverb_settings& halProperties,
+                           IEnvironmentalReverbEffect::AllProperties* properties);
+    void propertiesToHal(const IEnvironmentalReverbEffect::AllProperties& properties,
+                         t_reverb_settings* halProperties);
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.impl.h
new file mode 100644
index 0000000..9090b8a
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/EnvironmentalReverbEffect.impl.h
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <android/log.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+EnvironmentalReverbEffect::EnvironmentalReverbEffect(effect_handle_t handle)
+    : mEffect(new Effect(handle)) {}
+
+EnvironmentalReverbEffect::~EnvironmentalReverbEffect() {}
+
+void EnvironmentalReverbEffect::propertiesFromHal(
+    const t_reverb_settings& halProperties, IEnvironmentalReverbEffect::AllProperties* properties) {
+    properties->roomLevel = halProperties.roomLevel;
+    properties->roomHfLevel = halProperties.roomHFLevel;
+    properties->decayTime = halProperties.decayTime;
+    properties->decayHfRatio = halProperties.decayHFRatio;
+    properties->reflectionsLevel = halProperties.reflectionsLevel;
+    properties->reflectionsDelay = halProperties.reflectionsDelay;
+    properties->reverbLevel = halProperties.reverbLevel;
+    properties->reverbDelay = halProperties.reverbDelay;
+    properties->diffusion = halProperties.diffusion;
+    properties->density = halProperties.density;
+}
+
+void EnvironmentalReverbEffect::propertiesToHal(
+    const IEnvironmentalReverbEffect::AllProperties& properties, t_reverb_settings* halProperties) {
+    halProperties->roomLevel = properties.roomLevel;
+    halProperties->roomHFLevel = properties.roomHfLevel;
+    halProperties->decayTime = properties.decayTime;
+    halProperties->decayHFRatio = properties.decayHfRatio;
+    halProperties->reflectionsLevel = properties.reflectionsLevel;
+    halProperties->reflectionsDelay = properties.reflectionsDelay;
+    halProperties->reverbLevel = properties.reverbLevel;
+    halProperties->reverbDelay = properties.reverbDelay;
+    halProperties->diffusion = properties.diffusion;
+    halProperties->density = properties.density;
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> EnvironmentalReverbEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> EnvironmentalReverbEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> EnvironmentalReverbEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> EnvironmentalReverbEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> EnvironmentalReverbEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> EnvironmentalReverbEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> EnvironmentalReverbEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                                        setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::volumeChangeNotification(
+    const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> EnvironmentalReverbEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> EnvironmentalReverbEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> EnvironmentalReverbEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> EnvironmentalReverbEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setAuxChannelsConfig(
+    const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> EnvironmentalReverbEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> EnvironmentalReverbEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> EnvironmentalReverbEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                            const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> EnvironmentalReverbEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                                uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                                       const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> EnvironmentalReverbEffect::getParameter(const hidl_vec<uint8_t>& parameter,
+                                                     uint32_t valueMaxSize,
+                                                     getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> EnvironmentalReverbEffect::getCurrentConfigForFeature(
+    uint32_t featureId, uint32_t configSize, getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setCurrentConfigForFeature(
+    uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> EnvironmentalReverbEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEnvironmentalReverbEffect
+// follow.
+Return<Result> EnvironmentalReverbEffect::setBypass(bool bypass) {
+    return mEffect->setParam(REVERB_PARAM_BYPASS, bypass);
+}
+
+Return<void> EnvironmentalReverbEffect::getBypass(getBypass_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_BYPASS, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setRoomLevel(int16_t roomLevel) {
+    return mEffect->setParam(REVERB_PARAM_ROOM_LEVEL, roomLevel);
+}
+
+Return<void> EnvironmentalReverbEffect::getRoomLevel(getRoomLevel_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_ROOM_LEVEL, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setRoomHfLevel(int16_t roomHfLevel) {
+    return mEffect->setParam(REVERB_PARAM_ROOM_HF_LEVEL, roomHfLevel);
+}
+
+Return<void> EnvironmentalReverbEffect::getRoomHfLevel(getRoomHfLevel_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_ROOM_HF_LEVEL, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setDecayTime(uint32_t decayTime) {
+    return mEffect->setParam(REVERB_PARAM_DECAY_TIME, decayTime);
+}
+
+Return<void> EnvironmentalReverbEffect::getDecayTime(getDecayTime_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_DECAY_TIME, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setDecayHfRatio(int16_t decayHfRatio) {
+    return mEffect->setParam(REVERB_PARAM_DECAY_HF_RATIO, decayHfRatio);
+}
+
+Return<void> EnvironmentalReverbEffect::getDecayHfRatio(getDecayHfRatio_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_DECAY_HF_RATIO, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setReflectionsLevel(int16_t reflectionsLevel) {
+    return mEffect->setParam(REVERB_PARAM_REFLECTIONS_LEVEL, reflectionsLevel);
+}
+
+Return<void> EnvironmentalReverbEffect::getReflectionsLevel(getReflectionsLevel_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_REFLECTIONS_LEVEL, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setReflectionsDelay(uint32_t reflectionsDelay) {
+    return mEffect->setParam(REVERB_PARAM_REFLECTIONS_DELAY, reflectionsDelay);
+}
+
+Return<void> EnvironmentalReverbEffect::getReflectionsDelay(getReflectionsDelay_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_REFLECTIONS_DELAY, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setReverbLevel(int16_t reverbLevel) {
+    return mEffect->setParam(REVERB_PARAM_REVERB_LEVEL, reverbLevel);
+}
+
+Return<void> EnvironmentalReverbEffect::getReverbLevel(getReverbLevel_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_REVERB_LEVEL, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setReverbDelay(uint32_t reverbDelay) {
+    return mEffect->setParam(REVERB_PARAM_REVERB_DELAY, reverbDelay);
+}
+
+Return<void> EnvironmentalReverbEffect::getReverbDelay(getReverbDelay_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_REVERB_DELAY, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setDiffusion(int16_t diffusion) {
+    return mEffect->setParam(REVERB_PARAM_DIFFUSION, diffusion);
+}
+
+Return<void> EnvironmentalReverbEffect::getDiffusion(getDiffusion_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_DIFFUSION, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setDensity(int16_t density) {
+    return mEffect->setParam(REVERB_PARAM_DENSITY, density);
+}
+
+Return<void> EnvironmentalReverbEffect::getDensity(getDensity_cb _hidl_cb) {
+    return mEffect->getIntegerParam(REVERB_PARAM_DENSITY, _hidl_cb);
+}
+
+Return<Result> EnvironmentalReverbEffect::setAllProperties(
+    const IEnvironmentalReverbEffect::AllProperties& properties) {
+    t_reverb_settings halProperties;
+    propertiesToHal(properties, &halProperties);
+    return mEffect->setParam(REVERB_PARAM_PROPERTIES, halProperties);
+}
+
+Return<void> EnvironmentalReverbEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
+    t_reverb_settings halProperties;
+    Result retval = mEffect->getParam(REVERB_PARAM_PROPERTIES, halProperties);
+    AllProperties properties;
+    propertiesFromHal(halProperties, &properties);
+    _hidl_cb(retval, properties);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.h
new file mode 100644
index 0000000..c2b8ef8
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <vector>
+
+#include <system/audio_effects/effect_equalizer.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEqualizerEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct EqualizerEffect : public IEqualizerEffect {
+    explicit EqualizerEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEqualizerEffect follow.
+    Return<void> getNumBands(getNumBands_cb _hidl_cb) override;
+    Return<void> getLevelRange(getLevelRange_cb _hidl_cb) override;
+    Return<Result> setBandLevel(uint16_t band, int16_t level) override;
+    Return<void> getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb) override;
+    Return<void> getBandCenterFrequency(uint16_t band, getBandCenterFrequency_cb _hidl_cb) override;
+    Return<void> getBandFrequencyRange(uint16_t band, getBandFrequencyRange_cb _hidl_cb) override;
+    Return<void> getBandForFrequency(uint32_t freq, getBandForFrequency_cb _hidl_cb) override;
+    Return<void> getPresetNames(getPresetNames_cb _hidl_cb) override;
+    Return<Result> setCurrentPreset(uint16_t preset) override;
+    Return<void> getCurrentPreset(getCurrentPreset_cb _hidl_cb) override;
+    Return<Result> setAllProperties(const IEqualizerEffect::AllProperties& properties) override;
+    Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+
+    virtual ~EqualizerEffect();
+
+    void propertiesFromHal(const t_equalizer_settings& halProperties,
+                           IEqualizerEffect::AllProperties* properties);
+    std::vector<uint8_t> propertiesToHal(const IEqualizerEffect::AllProperties& properties,
+                                         t_equalizer_settings** halProperties);
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.impl.h
new file mode 100644
index 0000000..78485e4
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/EqualizerEffect.impl.h
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <memory.h>
+
+#include <android/log.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+EqualizerEffect::EqualizerEffect(effect_handle_t handle) : mEffect(new Effect(handle)) {}
+
+EqualizerEffect::~EqualizerEffect() {}
+
+void EqualizerEffect::propertiesFromHal(const t_equalizer_settings& halProperties,
+                                        IEqualizerEffect::AllProperties* properties) {
+    properties->curPreset = halProperties.curPreset;
+    // t_equalizer_settings incorrectly defines bandLevels as uint16_t,
+    // whereas the actual type of values used by effects is int16_t.
+    const int16_t* signedBandLevels =
+        reinterpret_cast<const int16_t*>(&halProperties.bandLevels[0]);
+    properties->bandLevels.setToExternal(const_cast<int16_t*>(signedBandLevels),
+                                         halProperties.numBands);
+}
+
+std::vector<uint8_t> EqualizerEffect::propertiesToHal(
+    const IEqualizerEffect::AllProperties& properties, t_equalizer_settings** halProperties) {
+    size_t bandsSize = properties.bandLevels.size() * sizeof(uint16_t);
+    std::vector<uint8_t> halBuffer(sizeof(t_equalizer_settings) + bandsSize, 0);
+    *halProperties = reinterpret_cast<t_equalizer_settings*>(&halBuffer[0]);
+    (*halProperties)->curPreset = properties.curPreset;
+    (*halProperties)->numBands = properties.bandLevels.size();
+    memcpy((*halProperties)->bandLevels, &properties.bandLevels[0], bandsSize);
+    return halBuffer;
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> EqualizerEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> EqualizerEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> EqualizerEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> EqualizerEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> EqualizerEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> EqualizerEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> EqualizerEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                              setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> EqualizerEffect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> EqualizerEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> EqualizerEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> EqualizerEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> EqualizerEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> EqualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> EqualizerEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> EqualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> EqualizerEffect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> EqualizerEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> EqualizerEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> EqualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> EqualizerEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> EqualizerEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                  const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> EqualizerEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                      uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> EqualizerEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                             const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> EqualizerEffect::getParameter(const hidl_vec<uint8_t>& parameter,
+                                           uint32_t valueMaxSize, getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> EqualizerEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> EqualizerEffect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                                         getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> EqualizerEffect::setCurrentConfigForFeature(uint32_t featureId,
+                                                           const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> EqualizerEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEqualizerEffect follow.
+Return<void> EqualizerEffect::getNumBands(getNumBands_cb _hidl_cb) {
+    return mEffect->getIntegerParam(EQ_PARAM_NUM_BANDS, _hidl_cb);
+}
+
+Return<void> EqualizerEffect::getLevelRange(getLevelRange_cb _hidl_cb) {
+    int16_t halLevels[2] = {0, 0};
+    Result retval = mEffect->getParam(EQ_PARAM_LEVEL_RANGE, halLevels);
+    _hidl_cb(retval, halLevels[0], halLevels[1]);
+    return Void();
+}
+
+Return<Result> EqualizerEffect::setBandLevel(uint16_t band, int16_t level) {
+    return mEffect->setParam(EQ_PARAM_BAND_LEVEL, band, level);
+}
+
+Return<void> EqualizerEffect::getBandLevel(uint16_t band, getBandLevel_cb _hidl_cb) {
+    int16_t halLevel = 0;
+    Result retval = mEffect->getParam(EQ_PARAM_BAND_LEVEL, band, halLevel);
+    _hidl_cb(retval, halLevel);
+    return Void();
+}
+
+Return<void> EqualizerEffect::getBandCenterFrequency(uint16_t band,
+                                                     getBandCenterFrequency_cb _hidl_cb) {
+    uint32_t halFreq = 0;
+    Result retval = mEffect->getParam(EQ_PARAM_CENTER_FREQ, band, halFreq);
+    _hidl_cb(retval, halFreq);
+    return Void();
+}
+
+Return<void> EqualizerEffect::getBandFrequencyRange(uint16_t band,
+                                                    getBandFrequencyRange_cb _hidl_cb) {
+    uint32_t halFreqs[2] = {0, 0};
+    Result retval = mEffect->getParam(EQ_PARAM_BAND_FREQ_RANGE, band, halFreqs);
+    _hidl_cb(retval, halFreqs[0], halFreqs[1]);
+    return Void();
+}
+
+Return<void> EqualizerEffect::getBandForFrequency(uint32_t freq, getBandForFrequency_cb _hidl_cb) {
+    uint16_t halBand = 0;
+    Result retval = mEffect->getParam(EQ_PARAM_GET_BAND, freq, halBand);
+    _hidl_cb(retval, halBand);
+    return Void();
+}
+
+Return<void> EqualizerEffect::getPresetNames(getPresetNames_cb _hidl_cb) {
+    uint16_t halPresetCount = 0;
+    Result retval = mEffect->getParam(EQ_PARAM_GET_NUM_OF_PRESETS, halPresetCount);
+    hidl_vec<hidl_string> presetNames;
+    if (retval == Result::OK) {
+        presetNames.resize(halPresetCount);
+        for (uint16_t i = 0; i < halPresetCount; ++i) {
+            char halPresetName[EFFECT_STRING_LEN_MAX];
+            retval = mEffect->getParam(EQ_PARAM_GET_PRESET_NAME, i, halPresetName);
+            if (retval == Result::OK) {
+                presetNames[i] = halPresetName;
+            } else {
+                presetNames.resize(i);
+            }
+        }
+    }
+    _hidl_cb(retval, presetNames);
+    return Void();
+}
+
+Return<Result> EqualizerEffect::setCurrentPreset(uint16_t preset) {
+    return mEffect->setParam(EQ_PARAM_CUR_PRESET, preset);
+}
+
+Return<void> EqualizerEffect::getCurrentPreset(getCurrentPreset_cb _hidl_cb) {
+    return mEffect->getIntegerParam(EQ_PARAM_CUR_PRESET, _hidl_cb);
+}
+
+Return<Result> EqualizerEffect::setAllProperties(
+    const IEqualizerEffect::AllProperties& properties) {
+    t_equalizer_settings* halPropertiesPtr = nullptr;
+    std::vector<uint8_t> halBuffer = propertiesToHal(properties, &halPropertiesPtr);
+    uint32_t paramId = EQ_PARAM_PROPERTIES;
+    return mEffect->setParameterImpl(sizeof(paramId), &paramId, halBuffer.size(), halPropertiesPtr);
+}
+
+Return<void> EqualizerEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
+    uint16_t numBands = 0;
+    Result retval = mEffect->getParam(EQ_PARAM_NUM_BANDS, numBands);
+    AllProperties properties;
+    if (retval != Result::OK) {
+        _hidl_cb(retval, properties);
+        return Void();
+    }
+    size_t valueSize = sizeof(t_equalizer_settings) + sizeof(int16_t) * numBands;
+    uint32_t paramId = EQ_PARAM_PROPERTIES;
+    retval = mEffect->getParameterImpl(
+        sizeof(paramId), &paramId, valueSize, [&](uint32_t, const void* valueData) {
+            const t_equalizer_settings* halProperties =
+                reinterpret_cast<const t_equalizer_settings*>(valueData);
+            propertiesFromHal(*halProperties, &properties);
+        });
+    _hidl_cb(retval, properties);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.h
new file mode 100644
index 0000000..e4f1bd5
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::ILoudnessEnhancerEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct LoudnessEnhancerEffect : public ILoudnessEnhancerEffect {
+    explicit LoudnessEnhancerEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::ILoudnessEnhancerEffect
+    // follow.
+    Return<Result> setTargetGain(int32_t targetGainMb) override;
+    Return<void> getTargetGain(getTargetGain_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+
+    virtual ~LoudnessEnhancerEffect();
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.impl.h
new file mode 100644
index 0000000..3f4f379
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/LoudnessEnhancerEffect.impl.h
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <system/audio_effects/effect_loudnessenhancer.h>
+
+#include <android/log.h>
+#include <system/audio_effects/effect_aec.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+LoudnessEnhancerEffect::LoudnessEnhancerEffect(effect_handle_t handle)
+    : mEffect(new Effect(handle)) {}
+
+LoudnessEnhancerEffect::~LoudnessEnhancerEffect() {}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> LoudnessEnhancerEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> LoudnessEnhancerEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> LoudnessEnhancerEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> LoudnessEnhancerEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> LoudnessEnhancerEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> LoudnessEnhancerEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> LoudnessEnhancerEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                                     setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> LoudnessEnhancerEffect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> LoudnessEnhancerEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> LoudnessEnhancerEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> LoudnessEnhancerEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> LoudnessEnhancerEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> LoudnessEnhancerEffect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> LoudnessEnhancerEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> LoudnessEnhancerEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> LoudnessEnhancerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> LoudnessEnhancerEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                         const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> LoudnessEnhancerEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                             uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> LoudnessEnhancerEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                                    const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> LoudnessEnhancerEffect::getParameter(const hidl_vec<uint8_t>& parameter,
+                                                  uint32_t valueMaxSize, getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> LoudnessEnhancerEffect::getCurrentConfigForFeature(
+    uint32_t featureId, uint32_t configSize, getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> LoudnessEnhancerEffect::setCurrentConfigForFeature(
+    uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> LoudnessEnhancerEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::ILoudnessEnhancerEffect
+// follow.
+Return<Result> LoudnessEnhancerEffect::setTargetGain(int32_t targetGainMb) {
+    return mEffect->setParam(LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB, targetGainMb);
+}
+
+Return<void> LoudnessEnhancerEffect::getTargetGain(getTargetGain_cb _hidl_cb) {
+    // AOSP Loudness Enhancer expects the size of the request to not include the
+    // size of the parameter.
+    uint32_t paramId = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB;
+    uint32_t targetGainMb = 0;
+    Result retval = mEffect->getParameterImpl(
+        sizeof(paramId), &paramId, 0, sizeof(targetGainMb), [&](uint32_t, const void* valueData) {
+            memcpy(&targetGainMb, valueData, sizeof(targetGainMb));
+        });
+    _hidl_cb(retval, targetGainMb);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.h
new file mode 100644
index 0000000..7b64ba0
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <system/audio_effects/effect_ns.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::INoiseSuppressionEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct NoiseSuppressionEffect : public INoiseSuppressionEffect {
+    explicit NoiseSuppressionEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::INoiseSuppressionEffect
+    // follow.
+    Return<Result> setSuppressionLevel(INoiseSuppressionEffect::Level level) override;
+    Return<void> getSuppressionLevel(getSuppressionLevel_cb _hidl_cb) override;
+    Return<Result> setSuppressionType(INoiseSuppressionEffect::Type type) override;
+    Return<void> getSuppressionType(getSuppressionType_cb _hidl_cb) override;
+    Return<Result> setAllProperties(
+        const INoiseSuppressionEffect::AllProperties& properties) override;
+    Return<void> getAllProperties(getAllProperties_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+
+    virtual ~NoiseSuppressionEffect();
+
+    void propertiesFromHal(const t_ns_settings& halProperties,
+                           INoiseSuppressionEffect::AllProperties* properties);
+    void propertiesToHal(const INoiseSuppressionEffect::AllProperties& properties,
+                         t_ns_settings* halProperties);
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.impl.h
new file mode 100644
index 0000000..e5fc454
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/NoiseSuppressionEffect.impl.h
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <android/log.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+NoiseSuppressionEffect::NoiseSuppressionEffect(effect_handle_t handle)
+    : mEffect(new Effect(handle)) {}
+
+NoiseSuppressionEffect::~NoiseSuppressionEffect() {}
+
+void NoiseSuppressionEffect::propertiesFromHal(const t_ns_settings& halProperties,
+                                               INoiseSuppressionEffect::AllProperties* properties) {
+    properties->level = Level(halProperties.level);
+    properties->type = Type(halProperties.type);
+}
+
+void NoiseSuppressionEffect::propertiesToHal(
+    const INoiseSuppressionEffect::AllProperties& properties, t_ns_settings* halProperties) {
+    halProperties->level = static_cast<uint32_t>(properties.level);
+    halProperties->type = static_cast<uint32_t>(properties.type);
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> NoiseSuppressionEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> NoiseSuppressionEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> NoiseSuppressionEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> NoiseSuppressionEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> NoiseSuppressionEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> NoiseSuppressionEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> NoiseSuppressionEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                                     setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> NoiseSuppressionEffect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> NoiseSuppressionEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> NoiseSuppressionEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> NoiseSuppressionEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> NoiseSuppressionEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> NoiseSuppressionEffect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> NoiseSuppressionEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> NoiseSuppressionEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> NoiseSuppressionEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> NoiseSuppressionEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                         const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> NoiseSuppressionEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                             uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> NoiseSuppressionEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                                    const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> NoiseSuppressionEffect::getParameter(const hidl_vec<uint8_t>& parameter,
+                                                  uint32_t valueMaxSize, getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> NoiseSuppressionEffect::getCurrentConfigForFeature(
+    uint32_t featureId, uint32_t configSize, getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> NoiseSuppressionEffect::setCurrentConfigForFeature(
+    uint32_t featureId, const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> NoiseSuppressionEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::INoiseSuppressionEffect
+// follow.
+Return<Result> NoiseSuppressionEffect::setSuppressionLevel(INoiseSuppressionEffect::Level level) {
+    return mEffect->setParam(NS_PARAM_LEVEL, static_cast<int32_t>(level));
+}
+
+Return<void> NoiseSuppressionEffect::getSuppressionLevel(getSuppressionLevel_cb _hidl_cb) {
+    int32_t halLevel = 0;
+    Result retval = mEffect->getParam(NS_PARAM_LEVEL, halLevel);
+    _hidl_cb(retval, Level(halLevel));
+    return Void();
+}
+
+Return<Result> NoiseSuppressionEffect::setSuppressionType(INoiseSuppressionEffect::Type type) {
+    return mEffect->setParam(NS_PARAM_TYPE, static_cast<int32_t>(type));
+}
+
+Return<void> NoiseSuppressionEffect::getSuppressionType(getSuppressionType_cb _hidl_cb) {
+    int32_t halType = 0;
+    Result retval = mEffect->getParam(NS_PARAM_TYPE, halType);
+    _hidl_cb(retval, Type(halType));
+    return Void();
+}
+
+Return<Result> NoiseSuppressionEffect::setAllProperties(
+    const INoiseSuppressionEffect::AllProperties& properties) {
+    t_ns_settings halProperties;
+    propertiesToHal(properties, &halProperties);
+    return mEffect->setParam(NS_PARAM_PROPERTIES, halProperties);
+}
+
+Return<void> NoiseSuppressionEffect::getAllProperties(getAllProperties_cb _hidl_cb) {
+    t_ns_settings halProperties;
+    Result retval = mEffect->getParam(NS_PARAM_PROPERTIES, halProperties);
+    AllProperties properties;
+    propertiesFromHal(halProperties, &properties);
+    _hidl_cb(retval, properties);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.h
new file mode 100644
index 0000000..3114acd
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IPresetReverbEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct PresetReverbEffect : public IPresetReverbEffect {
+    explicit PresetReverbEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IPresetReverbEffect
+    // follow.
+    Return<Result> setPreset(IPresetReverbEffect::Preset preset) override;
+    Return<void> getPreset(getPreset_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+
+    virtual ~PresetReverbEffect();
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.impl.h
new file mode 100644
index 0000000..32198d5
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/PresetReverbEffect.impl.h
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <android/log.h>
+#include <system/audio_effects/effect_presetreverb.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+PresetReverbEffect::PresetReverbEffect(effect_handle_t handle) : mEffect(new Effect(handle)) {}
+
+PresetReverbEffect::~PresetReverbEffect() {}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> PresetReverbEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> PresetReverbEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> PresetReverbEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> PresetReverbEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> PresetReverbEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> PresetReverbEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> PresetReverbEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                                 setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> PresetReverbEffect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> PresetReverbEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> PresetReverbEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> PresetReverbEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> PresetReverbEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> PresetReverbEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> PresetReverbEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> PresetReverbEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> PresetReverbEffect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> PresetReverbEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> PresetReverbEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> PresetReverbEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> PresetReverbEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> PresetReverbEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                     const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> PresetReverbEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                         uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> PresetReverbEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                                const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> PresetReverbEffect::getParameter(const hidl_vec<uint8_t>& parameter,
+                                              uint32_t valueMaxSize, getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> PresetReverbEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> PresetReverbEffect::getCurrentConfigForFeature(
+    uint32_t featureId, uint32_t configSize, getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> PresetReverbEffect::setCurrentConfigForFeature(uint32_t featureId,
+                                                              const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> PresetReverbEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IPresetReverbEffect follow.
+Return<Result> PresetReverbEffect::setPreset(IPresetReverbEffect::Preset preset) {
+    return mEffect->setParam(REVERB_PARAM_PRESET, static_cast<t_reverb_presets>(preset));
+}
+
+Return<void> PresetReverbEffect::getPreset(getPreset_cb _hidl_cb) {
+    t_reverb_presets halPreset = REVERB_PRESET_NONE;
+    Result retval = mEffect->getParam(REVERB_PARAM_PRESET, halPreset);
+    _hidl_cb(retval, Preset(halPreset));
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.h
new file mode 100644
index 0000000..3715894
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.h
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioChannelMask;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVirtualizerEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct VirtualizerEffect : public IVirtualizerEffect {
+    explicit VirtualizerEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVirtualizerEffect
+    // follow.
+    Return<bool> isStrengthSupported() override;
+    Return<Result> setStrength(uint16_t strength) override;
+    Return<void> getStrength(getStrength_cb _hidl_cb) override;
+    Return<void> getVirtualSpeakerAngles(AudioChannelMask mask, AudioDevice device,
+                                         getVirtualSpeakerAngles_cb _hidl_cb) override;
+    Return<Result> forceVirtualizationMode(AudioDevice device) override;
+    Return<void> getVirtualizationMode(getVirtualizationMode_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+
+    virtual ~VirtualizerEffect();
+
+    void speakerAnglesFromHal(const int32_t* halAngles, uint32_t channelCount,
+                              hidl_vec<SpeakerAngle>& speakerAngles);
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.impl.h
new file mode 100644
index 0000000..6fb8005
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/VirtualizerEffect.impl.h
@@ -0,0 +1,228 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <memory.h>
+
+#include <android/log.h>
+#include <system/audio_effects/effect_virtualizer.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+VirtualizerEffect::VirtualizerEffect(effect_handle_t handle) : mEffect(new Effect(handle)) {}
+
+VirtualizerEffect::~VirtualizerEffect() {}
+
+void VirtualizerEffect::speakerAnglesFromHal(const int32_t* halAngles, uint32_t channelCount,
+                                             hidl_vec<SpeakerAngle>& speakerAngles) {
+    speakerAngles.resize(channelCount);
+    for (uint32_t i = 0; i < channelCount; ++i) {
+        speakerAngles[i].mask = AudioChannelMask(*halAngles++);
+        speakerAngles[i].azimuth = *halAngles++;
+        speakerAngles[i].elevation = *halAngles++;
+    }
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> VirtualizerEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> VirtualizerEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> VirtualizerEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> VirtualizerEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> VirtualizerEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> VirtualizerEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> VirtualizerEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                                setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> VirtualizerEffect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> VirtualizerEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> VirtualizerEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> VirtualizerEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> VirtualizerEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> VirtualizerEffect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> VirtualizerEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> VirtualizerEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> VirtualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> VirtualizerEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> VirtualizerEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                    const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> VirtualizerEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                        uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> VirtualizerEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                               const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> VirtualizerEffect::getParameter(const hidl_vec<uint8_t>& parameter,
+                                             uint32_t valueMaxSize, getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                                           getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> VirtualizerEffect::setCurrentConfigForFeature(uint32_t featureId,
+                                                             const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> VirtualizerEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVirtualizerEffect follow.
+Return<bool> VirtualizerEffect::isStrengthSupported() {
+    bool halSupported = false;
+    mEffect->getParam(VIRTUALIZER_PARAM_STRENGTH_SUPPORTED, halSupported);
+    return halSupported;
+}
+
+Return<Result> VirtualizerEffect::setStrength(uint16_t strength) {
+    return mEffect->setParam(VIRTUALIZER_PARAM_STRENGTH, strength);
+}
+
+Return<void> VirtualizerEffect::getStrength(getStrength_cb _hidl_cb) {
+    return mEffect->getIntegerParam(VIRTUALIZER_PARAM_STRENGTH, _hidl_cb);
+}
+
+Return<void> VirtualizerEffect::getVirtualSpeakerAngles(AudioChannelMask mask, AudioDevice device,
+                                                        getVirtualSpeakerAngles_cb _hidl_cb) {
+    uint32_t channelCount =
+        audio_channel_count_from_out_mask(static_cast<audio_channel_mask_t>(mask));
+    size_t halSpeakerAnglesSize = sizeof(int32_t) * 3 * channelCount;
+    uint32_t halParam[3] = {VIRTUALIZER_PARAM_VIRTUAL_SPEAKER_ANGLES,
+                            static_cast<audio_channel_mask_t>(mask),
+                            static_cast<audio_devices_t>(device)};
+    hidl_vec<SpeakerAngle> speakerAngles;
+    Result retval = mEffect->getParameterImpl(
+        sizeof(halParam), halParam, halSpeakerAnglesSize,
+        [&](uint32_t valueSize, const void* valueData) {
+            if (valueSize > halSpeakerAnglesSize) {
+                valueSize = halSpeakerAnglesSize;
+            } else if (valueSize < halSpeakerAnglesSize) {
+                channelCount = valueSize / (sizeof(int32_t) * 3);
+            }
+            speakerAnglesFromHal(reinterpret_cast<const int32_t*>(valueData), channelCount,
+                                 speakerAngles);
+        });
+    _hidl_cb(retval, speakerAngles);
+    return Void();
+}
+
+Return<Result> VirtualizerEffect::forceVirtualizationMode(AudioDevice device) {
+    return mEffect->setParam(VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE,
+                             static_cast<audio_devices_t>(device));
+}
+
+Return<void> VirtualizerEffect::getVirtualizationMode(getVirtualizationMode_cb _hidl_cb) {
+    uint32_t halMode = 0;
+    Result retval = mEffect->getParam(VIRTUALIZER_PARAM_FORCE_VIRTUALIZATION_MODE, halMode);
+    _hidl_cb(retval, AudioDevice(halMode));
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.h b/audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.h
new file mode 100644
index 0000000..8050221
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.h
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <hidl/Status.h>
+
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioDevice;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioMode;
+using ::android::hardware::audio::common::AUDIO_HAL_VERSION::AudioSource;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::AudioBuffer;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectAuxChannelsConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectConfig;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectDescriptor;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::EffectOffloadParameter;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffectBufferProviderCallback;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVisualizerEffect;
+using ::android::hardware::audio::effect::AUDIO_HAL_VERSION::Result;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct VisualizerEffect : public IVisualizerEffect {
+    explicit VisualizerEffect(effect_handle_t handle);
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+    Return<Result> init() override;
+    Return<Result> setConfig(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> reset() override;
+    Return<Result> enable() override;
+    Return<Result> disable() override;
+    Return<Result> setDevice(AudioDevice device) override;
+    Return<void> setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                 setAndGetVolume_cb _hidl_cb) override;
+    Return<Result> volumeChangeNotification(const hidl_vec<uint32_t>& volumes) override;
+    Return<Result> setAudioMode(AudioMode mode) override;
+    Return<Result> setConfigReverse(
+        const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+        const sp<IEffectBufferProviderCallback>& outputBufferProvider) override;
+    Return<Result> setInputDevice(AudioDevice device) override;
+    Return<void> getConfig(getConfig_cb _hidl_cb) override;
+    Return<void> getConfigReverse(getConfigReverse_cb _hidl_cb) override;
+    Return<void> getSupportedAuxChannelsConfigs(
+        uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) override;
+    Return<void> getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) override;
+    Return<Result> setAuxChannelsConfig(const EffectAuxChannelsConfig& config) override;
+    Return<Result> setAudioSource(AudioSource source) override;
+    Return<Result> offload(const EffectOffloadParameter& param) override;
+    Return<void> getDescriptor(getDescriptor_cb _hidl_cb) override;
+    Return<void> prepareForProcessing(prepareForProcessing_cb _hidl_cb) override;
+    Return<Result> setProcessBuffers(const AudioBuffer& inBuffer,
+                                     const AudioBuffer& outBuffer) override;
+    Return<void> command(uint32_t commandId, const hidl_vec<uint8_t>& data, uint32_t resultMaxSize,
+                         command_cb _hidl_cb) override;
+    Return<Result> setParameter(const hidl_vec<uint8_t>& parameter,
+                                const hidl_vec<uint8_t>& value) override;
+    Return<void> getParameter(const hidl_vec<uint8_t>& parameter, uint32_t valueMaxSize,
+                              getParameter_cb _hidl_cb) override;
+    Return<void> getSupportedConfigsForFeature(uint32_t featureId, uint32_t maxConfigs,
+                                               uint32_t configSize,
+                                               getSupportedConfigsForFeature_cb _hidl_cb) override;
+    Return<void> getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                            getCurrentConfigForFeature_cb _hidl_cb) override;
+    Return<Result> setCurrentConfigForFeature(uint32_t featureId,
+                                              const hidl_vec<uint8_t>& configData) override;
+    Return<Result> close() override;
+
+    // Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVisualizerEffect follow.
+    Return<Result> setCaptureSize(uint16_t captureSize) override;
+    Return<void> getCaptureSize(getCaptureSize_cb _hidl_cb) override;
+    Return<Result> setScalingMode(IVisualizerEffect::ScalingMode scalingMode) override;
+    Return<void> getScalingMode(getScalingMode_cb _hidl_cb) override;
+    Return<Result> setLatency(uint32_t latencyMs) override;
+    Return<void> getLatency(getLatency_cb _hidl_cb) override;
+    Return<Result> setMeasurementMode(IVisualizerEffect::MeasurementMode measurementMode) override;
+    Return<void> getMeasurementMode(getMeasurementMode_cb _hidl_cb) override;
+    Return<void> capture(capture_cb _hidl_cb) override;
+    Return<void> measure(measure_cb _hidl_cb) override;
+
+   private:
+    sp<Effect> mEffect;
+    uint16_t mCaptureSize;
+    MeasurementMode mMeasurementMode;
+
+    virtual ~VisualizerEffect();
+};
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.impl.h
new file mode 100644
index 0000000..0351453
--- /dev/null
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/VisualizerEffect.impl.h
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+
+#include <common/all-versions/IncludeGuard.h>
+
+#include <android/log.h>
+#include <system/audio_effects/effect_visualizer.h>
+
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace AUDIO_HAL_VERSION {
+namespace implementation {
+
+VisualizerEffect::VisualizerEffect(effect_handle_t handle)
+    : mEffect(new Effect(handle)), mCaptureSize(0), mMeasurementMode(MeasurementMode::NONE) {}
+
+VisualizerEffect::~VisualizerEffect() {}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IEffect follow.
+Return<Result> VisualizerEffect::init() {
+    return mEffect->init();
+}
+
+Return<Result> VisualizerEffect::setConfig(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfig(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> VisualizerEffect::reset() {
+    return mEffect->reset();
+}
+
+Return<Result> VisualizerEffect::enable() {
+    return mEffect->enable();
+}
+
+Return<Result> VisualizerEffect::disable() {
+    return mEffect->disable();
+}
+
+Return<Result> VisualizerEffect::setDevice(AudioDevice device) {
+    return mEffect->setDevice(device);
+}
+
+Return<void> VisualizerEffect::setAndGetVolume(const hidl_vec<uint32_t>& volumes,
+                                               setAndGetVolume_cb _hidl_cb) {
+    return mEffect->setAndGetVolume(volumes, _hidl_cb);
+}
+
+Return<Result> VisualizerEffect::volumeChangeNotification(const hidl_vec<uint32_t>& volumes) {
+    return mEffect->volumeChangeNotification(volumes);
+}
+
+Return<Result> VisualizerEffect::setAudioMode(AudioMode mode) {
+    return mEffect->setAudioMode(mode);
+}
+
+Return<Result> VisualizerEffect::setConfigReverse(
+    const EffectConfig& config, const sp<IEffectBufferProviderCallback>& inputBufferProvider,
+    const sp<IEffectBufferProviderCallback>& outputBufferProvider) {
+    return mEffect->setConfigReverse(config, inputBufferProvider, outputBufferProvider);
+}
+
+Return<Result> VisualizerEffect::setInputDevice(AudioDevice device) {
+    return mEffect->setInputDevice(device);
+}
+
+Return<void> VisualizerEffect::getConfig(getConfig_cb _hidl_cb) {
+    return mEffect->getConfig(_hidl_cb);
+}
+
+Return<void> VisualizerEffect::getConfigReverse(getConfigReverse_cb _hidl_cb) {
+    return mEffect->getConfigReverse(_hidl_cb);
+}
+
+Return<void> VisualizerEffect::getSupportedAuxChannelsConfigs(
+    uint32_t maxConfigs, getSupportedAuxChannelsConfigs_cb _hidl_cb) {
+    return mEffect->getSupportedAuxChannelsConfigs(maxConfigs, _hidl_cb);
+}
+
+Return<void> VisualizerEffect::getAuxChannelsConfig(getAuxChannelsConfig_cb _hidl_cb) {
+    return mEffect->getAuxChannelsConfig(_hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setAuxChannelsConfig(const EffectAuxChannelsConfig& config) {
+    return mEffect->setAuxChannelsConfig(config);
+}
+
+Return<Result> VisualizerEffect::setAudioSource(AudioSource source) {
+    return mEffect->setAudioSource(source);
+}
+
+Return<Result> VisualizerEffect::offload(const EffectOffloadParameter& param) {
+    return mEffect->offload(param);
+}
+
+Return<void> VisualizerEffect::getDescriptor(getDescriptor_cb _hidl_cb) {
+    return mEffect->getDescriptor(_hidl_cb);
+}
+
+Return<void> VisualizerEffect::prepareForProcessing(prepareForProcessing_cb _hidl_cb) {
+    return mEffect->prepareForProcessing(_hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setProcessBuffers(const AudioBuffer& inBuffer,
+                                                   const AudioBuffer& outBuffer) {
+    return mEffect->setProcessBuffers(inBuffer, outBuffer);
+}
+
+Return<void> VisualizerEffect::command(uint32_t commandId, const hidl_vec<uint8_t>& data,
+                                       uint32_t resultMaxSize, command_cb _hidl_cb) {
+    return mEffect->command(commandId, data, resultMaxSize, _hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setParameter(const hidl_vec<uint8_t>& parameter,
+                                              const hidl_vec<uint8_t>& value) {
+    return mEffect->setParameter(parameter, value);
+}
+
+Return<void> VisualizerEffect::getParameter(const hidl_vec<uint8_t>& parameter,
+                                            uint32_t valueMaxSize, getParameter_cb _hidl_cb) {
+    return mEffect->getParameter(parameter, valueMaxSize, _hidl_cb);
+}
+
+Return<void> VisualizerEffect::getSupportedConfigsForFeature(
+    uint32_t featureId, uint32_t maxConfigs, uint32_t configSize,
+    getSupportedConfigsForFeature_cb _hidl_cb) {
+    return mEffect->getSupportedConfigsForFeature(featureId, maxConfigs, configSize, _hidl_cb);
+}
+
+Return<void> VisualizerEffect::getCurrentConfigForFeature(uint32_t featureId, uint32_t configSize,
+                                                          getCurrentConfigForFeature_cb _hidl_cb) {
+    return mEffect->getCurrentConfigForFeature(featureId, configSize, _hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setCurrentConfigForFeature(uint32_t featureId,
+                                                            const hidl_vec<uint8_t>& configData) {
+    return mEffect->setCurrentConfigForFeature(featureId, configData);
+}
+
+Return<Result> VisualizerEffect::close() {
+    return mEffect->close();
+}
+
+// Methods from ::android::hardware::audio::effect::AUDIO_HAL_VERSION::IVisualizerEffect follow.
+Return<Result> VisualizerEffect::setCaptureSize(uint16_t captureSize) {
+    Result retval = mEffect->setParam(VISUALIZER_PARAM_CAPTURE_SIZE, captureSize);
+    if (retval == Result::OK) {
+        mCaptureSize = captureSize;
+    }
+    return retval;
+}
+
+Return<void> VisualizerEffect::getCaptureSize(getCaptureSize_cb _hidl_cb) {
+    return mEffect->getIntegerParam(VISUALIZER_PARAM_CAPTURE_SIZE, _hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setScalingMode(IVisualizerEffect::ScalingMode scalingMode) {
+    return mEffect->setParam(VISUALIZER_PARAM_SCALING_MODE, static_cast<int32_t>(scalingMode));
+}
+
+Return<void> VisualizerEffect::getScalingMode(getScalingMode_cb _hidl_cb) {
+    int32_t halMode;
+    Result retval = mEffect->getParam(VISUALIZER_PARAM_SCALING_MODE, halMode);
+    _hidl_cb(retval, ScalingMode(halMode));
+    return Void();
+}
+
+Return<Result> VisualizerEffect::setLatency(uint32_t latencyMs) {
+    return mEffect->setParam(VISUALIZER_PARAM_LATENCY, latencyMs);
+}
+
+Return<void> VisualizerEffect::getLatency(getLatency_cb _hidl_cb) {
+    return mEffect->getIntegerParam(VISUALIZER_PARAM_LATENCY, _hidl_cb);
+}
+
+Return<Result> VisualizerEffect::setMeasurementMode(
+    IVisualizerEffect::MeasurementMode measurementMode) {
+    Result retval =
+        mEffect->setParam(VISUALIZER_PARAM_MEASUREMENT_MODE, static_cast<int32_t>(measurementMode));
+    if (retval == Result::OK) {
+        mMeasurementMode = measurementMode;
+    }
+    return retval;
+}
+
+Return<void> VisualizerEffect::getMeasurementMode(getMeasurementMode_cb _hidl_cb) {
+    int32_t halMode;
+    Result retval = mEffect->getParam(VISUALIZER_PARAM_MEASUREMENT_MODE, halMode);
+    _hidl_cb(retval, MeasurementMode(halMode));
+    return Void();
+}
+
+Return<void> VisualizerEffect::capture(capture_cb _hidl_cb) {
+    if (mCaptureSize == 0) {
+        _hidl_cb(Result::NOT_INITIALIZED, hidl_vec<uint8_t>());
+        return Void();
+    }
+    uint32_t halCaptureSize = mCaptureSize;
+    uint8_t halCapture[mCaptureSize];
+    Result retval = mEffect->sendCommandReturningData(VISUALIZER_CMD_CAPTURE, "VISUALIZER_CAPTURE",
+                                                      &halCaptureSize, halCapture);
+    hidl_vec<uint8_t> capture;
+    if (retval == Result::OK) {
+        capture.setToExternal(&halCapture[0], halCaptureSize);
+    }
+    _hidl_cb(retval, capture);
+    return Void();
+}
+
+Return<void> VisualizerEffect::measure(measure_cb _hidl_cb) {
+    if (mMeasurementMode == MeasurementMode::NONE) {
+        _hidl_cb(Result::NOT_INITIALIZED, Measurement());
+        return Void();
+    }
+    int32_t halMeasurement[MEASUREMENT_COUNT];
+    uint32_t halMeasurementSize = sizeof(halMeasurement);
+    Result retval = mEffect->sendCommandReturningData(VISUALIZER_CMD_MEASURE, "VISUALIZER_MEASURE",
+                                                      &halMeasurementSize, halMeasurement);
+    Measurement measurement = {.mode = MeasurementMode::PEAK_RMS};
+    measurement.value.peakAndRms.peakMb = 0;
+    measurement.value.peakAndRms.rmsMb = 0;
+    if (retval == Result::OK) {
+        measurement.value.peakAndRms.peakMb = halMeasurement[MEASUREMENT_IDX_PEAK];
+        measurement.value.peakAndRms.rmsMb = halMeasurement[MEASUREMENT_IDX_RMS];
+    }
+    _hidl_cb(retval, measurement);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace AUDIO_HAL_VERSION
+}  // namespace effect
+}  // namespace audio
+}  // namespace hardware
+}  // namespace android
diff --git a/authsecret/1.0/Android.bp b/authsecret/1.0/Android.bp
new file mode 100644
index 0000000..9cde99a
--- /dev/null
+++ b/authsecret/1.0/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.authsecret@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IAuthSecret.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
+
diff --git a/authsecret/1.0/IAuthSecret.hal b/authsecret/1.0/IAuthSecret.hal
new file mode 100644
index 0000000..6b573b3
--- /dev/null
+++ b/authsecret/1.0/IAuthSecret.hal
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.authsecret@1.0;
+
+/**
+ * This security HAL allows vendor components to be cryptographically tied to
+ * the primary user's credential. For example, security hardware could require
+ * proof that the credential is known before applying updates.
+ *
+ * This HAL is optional so does not require an implementation on device.
+ */
+interface IAuthSecret {
+    /**
+     * When the primary user is unlocked, this method is passed a secret to
+     * prove that is has been successfully unlocked. The primary user can either
+     * be unlocked by a person entering their credential or by another party
+     * using an escrow token e.g. a device administrator.
+     *
+     * The first time this is called, the secret must be used to provision state
+     * that depends on the primary user's secret. The same secret must be passed
+     * on each call until the next factory reset.
+     *
+     * Upon factory reset, any dependence on the secret must be removed as that
+     * secret is now lost and must never be derived again. A new secret must be
+     * created for the new primary user which must be used to newly provision
+     * state the first time this method is called after factory reset.
+     *
+     * The secret must be at least 16 bytes.
+     *
+     * @param secret blob derived from the primary user's credential.
+     */
+    primaryUserCredential(vec<uint8_t> secret);
+};
diff --git a/authsecret/1.0/default/Android.bp b/authsecret/1.0/default/Android.bp
new file mode 100644
index 0000000..5c3234f
--- /dev/null
+++ b/authsecret/1.0/default/Android.bp
@@ -0,0 +1,21 @@
+cc_binary {
+    name: "android.hardware.authsecret@1.0-service",
+    init_rc: ["android.hardware.authsecret@1.0-service.rc"],
+    relative_install_path: "hw",
+    vendor: true,
+    srcs: [
+        "service.cpp",
+        "AuthSecret.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "android.hardware.authsecret@1.0",
+    ],
+}
diff --git a/authsecret/1.0/default/AuthSecret.cpp b/authsecret/1.0/default/AuthSecret.cpp
new file mode 100644
index 0000000..f9271e9
--- /dev/null
+++ b/authsecret/1.0/default/AuthSecret.cpp
@@ -0,0 +1,43 @@
+#include "AuthSecret.h"
+
+namespace android {
+namespace hardware {
+namespace authsecret {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::authsecret::V1_0::IAuthSecret follow.
+Return<void> AuthSecret::primaryUserCredential(const hidl_vec<uint8_t>& secret) {
+    (void)secret;
+
+    // To create a dependency on the credential, it is recommended to derive a
+    // different value from the provided secret for each purpose e.g.
+    //
+    //     purpose1_secret = hash( "purpose1" || secret )
+    //     purpose2_secret = hash( "purpose2" || secret )
+    //
+    // The derived values can then be used as cryptographic keys or stored
+    // securely for comparison in a future call.
+    //
+    // For example, a security module might require that the credential has been
+    // entered before it applies any updates. This can be achieved by storing a
+    // derived value in the module and only applying updates when the same
+    // derived value is presented again.
+    //
+    // This implementation does nothing.
+
+    return Void();
+}
+
+// Note: on factory reset, clear all dependency on the secret.
+//
+// With the example of updating a security module, the stored value must be
+// cleared so that the new primary user enrolled as the approver of updates.
+//
+// This implementation does nothing as there is no dependence on the secret.
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace authsecret
+}  // namespace hardware
+}  // namespace android
diff --git a/authsecret/1.0/default/AuthSecret.h b/authsecret/1.0/default/AuthSecret.h
new file mode 100644
index 0000000..387fa67
--- /dev/null
+++ b/authsecret/1.0/default/AuthSecret.h
@@ -0,0 +1,35 @@
+#ifndef ANDROID_HARDWARE_AUTHSECRET_V1_0_AUTHSECRET_H
+#define ANDROID_HARDWARE_AUTHSECRET_V1_0_AUTHSECRET_H
+
+#include <android/hardware/authsecret/1.0/IAuthSecret.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace authsecret {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct AuthSecret : public IAuthSecret {
+    // Methods from ::android::hardware::authsecret::V1_0::IAuthSecret follow.
+    Return<void> primaryUserCredential(const hidl_vec<uint8_t>& secret) override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace authsecret
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUTHSECRET_V1_0_AUTHSECRET_H
diff --git a/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc b/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc
new file mode 100644
index 0000000..e82da7e
--- /dev/null
+++ b/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.authsecret-1-0 /vendor/bin/hw/android.hardware.authsecret@1.0-service
+    class hal
+    user system
+    group system
diff --git a/authsecret/1.0/default/service.cpp b/authsecret/1.0/default/service.cpp
new file mode 100644
index 0000000..4acd16c
--- /dev/null
+++ b/authsecret/1.0/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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.authsecret@1.0-service"
+
+#include <android/hardware/authsecret/1.0/IAuthSecret.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "AuthSecret.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::authsecret::V1_0::IAuthSecret;
+using android::hardware::authsecret::V1_0::implementation::AuthSecret;
+using android::sp;
+using android::status_t;
+using android::OK;
+
+int main() {
+    configureRpcThreadpool(1, true);
+
+    sp<IAuthSecret> authSecret = new AuthSecret;
+    status_t status = authSecret->registerAsService();
+    LOG_ALWAYS_FATAL_IF(status != OK, "Could not register IAuthSecret");
+
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/authsecret/1.0/vts/functional/Android.bp b/authsecret/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..de9f560
--- /dev/null
+++ b/authsecret/1.0/vts/functional/Android.bp
@@ -0,0 +1,22 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalAuthSecretV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalAuthSecretV1_0TargetTest.cpp"],
+    static_libs: ["android.hardware.authsecret@1.0"],
+}
diff --git a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
new file mode 100644
index 0000000..a610a75
--- /dev/null
+++ b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/authsecret/1.0/IAuthSecret.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::authsecret::V1_0::IAuthSecret;
+using ::android::sp;
+
+/**
+ * There is no expected behaviour that can be tested so these tests check the
+ * HAL doesn't crash with different execution orders.
+ */
+struct AuthSecretHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+    virtual void SetUp() override {
+        authsecret = ::testing::VtsHalHidlTargetTestBase::getService<IAuthSecret>();
+        ASSERT_NE(authsecret, nullptr);
+
+        // All tests must enroll the correct secret first as this cannot be changed
+        // without a factory reset and the order of tests could change.
+        authsecret->primaryUserCredential(CORRECT_SECRET);
+    }
+
+    sp<IAuthSecret> authsecret;
+    hidl_vec<uint8_t> CORRECT_SECRET{61, 93, 124, 240, 5, 0, 7, 201, 9, 129, 11, 12, 0, 14, 0, 16};
+    hidl_vec<uint8_t> WRONG_SECRET{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+};
+
+/* Provision the primary user with a secret. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredential) {
+    // Secret provisioned by SetUp()
+}
+
+/* Provision the primary user with a secret and pass the secret again. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgain) {
+    // Secret provisioned by SetUp()
+    authsecret->primaryUserCredential(CORRECT_SECRET);
+}
+
+/* Provision the primary user with a secret and pass the secret again repeatedly. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgainMultipleTimes) {
+    // Secret provisioned by SetUp()
+    constexpr int N = 5;
+    for (int i = 0; i < N; ++i) {
+        authsecret->primaryUserCredential(CORRECT_SECRET);
+    }
+}
+
+/* Provision the primary user with a secret and then pass the wrong secret. This
+ * should never happen and is an framework bug if it does. As the secret is
+ * wrong, the HAL implementation may not be able to function correctly but it
+ * should fail gracefully. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndWrongSecret) {
+    // Secret provisioned by SetUp()
+    authsecret->primaryUserCredential(WRONG_SECRET);
+}
diff --git a/automotive/audiocontrol/1.0/Android.bp b/automotive/audiocontrol/1.0/Android.bp
new file mode 100644
index 0000000..9335a6c
--- /dev/null
+++ b/automotive/audiocontrol/1.0/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.automotive.audiocontrol@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IAudioControl.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "ContextNumber",
+    ],
+    gen_java: true,
+}
+
diff --git a/automotive/audiocontrol/1.0/IAudioControl.hal b/automotive/audiocontrol/1.0/IAudioControl.hal
new file mode 100644
index 0000000..c029499
--- /dev/null
+++ b/automotive/audiocontrol/1.0/IAudioControl.hal
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@1.0;
+
+
+/**
+ * Interacts with the car's audio subsystem to manage audio sources and volumes
+ */
+interface IAudioControl {
+
+    /**
+     * Called at startup once per context to get the mapping from ContextNumber to
+     * busAddress. This lets the car tell the framework to which physical output stream
+     * each context should be routed.
+     *
+     * For every context, a valid bus number (0 - num busses-1) must be returned. If an
+     * unrecognized contextNumber is encountered, then -1 shall be returned.
+     *
+     * Any context for which an invalid busNumber is returned must be routed to bus 0.
+     */
+    getBusForContext(uint32_t contextNumber)
+        generates (int32_t busNumber);
+
+
+    /**
+     * Control the right/left balance setting of the car speakers.
+     *
+     * This is intended to shift the speaker volume toward the right (+) or left (-) side of
+     * the car. 0.0 means "centered". +1.0 means fully right. -1.0 means fully left.
+     *
+     * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
+     * range.
+     */
+    oneway setBalanceTowardRight(float value);
+
+
+    /**
+     * Control the fore/aft fade setting of the car speakers.
+     *
+     * This is intended to shift the speaker volume toward the front (+) or back (-) of the car.
+     * 0.0 means "centered". +1.0 means fully forward. -1.0 means fully rearward.
+     *
+     * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
+     * range.
+     */
+    oneway setFadeTowardFront(float value);
+};
+
diff --git a/automotive/audiocontrol/1.0/default/Android.bp b/automotive/audiocontrol/1.0/default/Android.bp
new file mode 100644
index 0000000..0e074dd
--- /dev/null
+++ b/automotive/audiocontrol/1.0/default/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+    name: "android.hardware.automotive.audiocontrol@1.0-service",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "AudioControl.cpp",
+        "service.cpp"
+    ],
+    init_rc: ["android.hardware.automotive.audiocontrol@1.0-service.rc"],
+
+    shared_libs: [
+        "android.hardware.automotive.audiocontrol@1.0",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+
+    cflags: [
+        "-DLOG_TAG=\"AudCntrlDrv\"",
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/automotive/audiocontrol/1.0/default/AudioControl.cpp b/automotive/audiocontrol/1.0/default/AudioControl.cpp
new file mode 100644
index 0000000..b40f2ae
--- /dev/null
+++ b/automotive/audiocontrol/1.0/default/AudioControl.cpp
@@ -0,0 +1,77 @@
+#include "AudioControl.h"
+
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace audiocontrol {
+namespace V1_0 {
+namespace implementation {
+
+
+// This is the static map we're using to associate a ContextNumber with a
+// bus number from the audio_policy_configuration.xml setup.  Every valid context needs
+// to be mapped to a bus address that actually exists in the platforms configuration.
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))  // Would be nice if this were common...
+static int sContextToBusMap[] = {
+    -1,     // INVALID
+     0,     // MUSIC_CONTEXT
+     1,     // NAVIGATION_CONTEXT
+     2,     // VOICE_COMMAND_CONTEXT
+     3,     // CALL_RING_CONTEXT
+     4,     // CALL_CONTEXT
+     5,     // ALARM_CONTEXT
+     6,     // NOTIFICATION_CONTEXT
+     7,     // SYSTEM_SOUND_CONTEXT
+};
+static const unsigned sContextMapSize = ARRAY_SIZE(sContextToBusMap);
+static const unsigned sContextCount = sContextMapSize - 1;  // Less one for the INVALID entry
+static const unsigned sContextNumberMax = sContextCount;    // contextNumber is counted from 1
+
+
+AudioControl::AudioControl() {
+};
+
+
+Return<int32_t> AudioControl::getBusForContext(uint32_t contextNumber) {
+    if (contextNumber > sContextNumberMax) {
+        ALOGE("Unexpected context number %d (max expected is %d)", contextNumber, sContextCount);
+        return -1;
+    } else {
+        return sContextToBusMap[contextNumber];
+    }
+}
+
+
+Return<void> AudioControl::setBalanceTowardRight(float value) {
+    // For completeness, lets bounds check the input...
+    if ((value > 1.0f) || (value < -1.0f)) {
+        ALOGE("Balance value out of range -1 to 1 at %0.2f", value);
+    } else {
+        // Just log in this default mock implementation
+        ALOGI("Balance set to %0.2f", value);
+    }
+    return Void();
+}
+
+
+Return<void> AudioControl::setFadeTowardFront(float value) {
+    // For completeness, lets bounds check the input...
+    if ((value > 1.0f) || (value < -1.0f)) {
+        ALOGE("Fader value out of range -1 to 1 at %0.2f", value);
+    } else {
+        // Just log in this default mock implementation
+        ALOGI("Fader set to %0.2f", value);
+    }
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace audiocontrol
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/audiocontrol/1.0/default/AudioControl.h b/automotive/audiocontrol/1.0/default/AudioControl.h
new file mode 100644
index 0000000..89e41f9
--- /dev/null
+++ b/automotive/audiocontrol/1.0/default/AudioControl.h
@@ -0,0 +1,41 @@
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V1_0_AUDIOCONTROL_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V1_0_AUDIOCONTROL_H
+
+#include <android/hardware/automotive/audiocontrol/1.0/IAudioControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace audiocontrol {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct AudioControl : public IAudioControl {
+public:
+    // Methods from ::android::hardware::automotive::audiocontrol::V1_0::IAudioControl follow.
+    Return<int32_t> getBusForContext(uint32_t contextNumber) override;
+    Return<void> setBalanceTowardRight(float value) override;
+    Return<void> setFadeTowardFront(float value) override;
+
+    // Implementation details
+    AudioControl();
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace audiocontrol
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V1_0_AUDIOCONTROL_H
diff --git a/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc b/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc
new file mode 100644
index 0000000..c02db08
--- /dev/null
+++ b/automotive/audiocontrol/1.0/default/android.hardware.automotive.audiocontrol@1.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.audiocontrol-hal-1.0 /vendor/bin/hw/android.hardware.automotive.audiocontrol@1.0-service
+    class hal
+    user audioserver
+    group system
diff --git a/automotive/audiocontrol/1.0/default/service.cpp b/automotive/audiocontrol/1.0/default/service.cpp
new file mode 100644
index 0000000..a033fd9
--- /dev/null
+++ b/automotive/audiocontrol/1.0/default/service.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <unistd.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "AudioControl.h"
+
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::automotive::audiocontrol::V1_0::IAudioControl;
+
+// The namespace in which all our implementation code lives
+using namespace android::hardware::automotive::audiocontrol::V1_0::implementation;
+using namespace android;
+
+
+// Main service entry point
+int main() {
+    // Create an instance of our service class
+    android::sp<IAudioControl> service = new AudioControl();
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+    if (service->registerAsService() != OK) {
+        ALOGE("registerAsService failed");
+        return 1;
+    }
+
+    // Join (forever) the thread pool we created for the service above
+    joinRpcThreadpool();
+
+    // We don't ever actually expect to return, so return an error if we do get here
+    return 2;
+}
\ No newline at end of file
diff --git a/automotive/audiocontrol/1.0/types.hal b/automotive/audiocontrol/1.0/types.hal
new file mode 100644
index 0000000..04d8d35
--- /dev/null
+++ b/automotive/audiocontrol/1.0/types.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@1.0;
+
+
+/**
+ * Predefined flags to identifying audio contexts
+ */
+enum ContextNumber : uint32_t {
+    INVALID = 0,    /* Shouldn't be used */
+
+    // Sounds from Android (counting from 1 coincidentally lets us match AudioAttributes usages)
+    MUSIC,          /* Music playback */
+    NAVIGATION,     /* Navigation directions */
+    VOICE_COMMAND,  /* Voice command session */
+    CALL_RING,      /* Voice call ringing */
+    CALL,           /* Voice call */
+    ALARM,          /* Alarm sound from Android */
+    NOTIFICATION,   /* Notifications */
+    SYSTEM_SOUND,   /* User interaction sounds (button clicks, etc) */
+};
diff --git a/automotive/evs/1.0/default/Android.bp b/automotive/evs/1.0/default/Android.bp
index 2574e86..7286478 100644
--- a/automotive/evs/1.0/default/Android.bp
+++ b/automotive/evs/1.0/default/Android.bp
@@ -13,7 +13,6 @@
 
     shared_libs: [
         "android.hardware.automotive.evs@1.0",
-        "libui",
         "libbase",
         "libbinder",
         "libcutils",
@@ -21,6 +20,7 @@
         "libhidlbase",
         "libhidltransport",
         "liblog",
+        "libui",
         "libutils",
     ],
 
diff --git a/automotive/evs/1.0/default/ServiceNames.h b/automotive/evs/1.0/default/ServiceNames.h
index d20a37f..1178da5 100644
--- a/automotive/evs/1.0/default/ServiceNames.h
+++ b/automotive/evs/1.0/default/ServiceNames.h
@@ -14,4 +14,4 @@
  * limitations under the License.
  */
 
-const static char kEnumeratorServiceName[] = "EvsEnumeratorHw-Mock";
+const static char kEnumeratorServiceName[] = "EvsEnumeratorHw";
diff --git a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
index 16d521d..117c249 100644
--- a/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
+++ b/automotive/evs/1.0/default/android.hardware.automotive.evs@1.0-service.rc
@@ -1,4 +1,4 @@
-service evs-hal-mock /vendor/bin/hw/android.hardware.automotive.evs@1.0-service
+service vendor.evs-hal-mock /vendor/bin/hw/android.hardware.automotive.evs@1.0-service
     class hal
     user automotive_evs
     group automotive_evs
diff --git a/automotive/evs/1.0/vts/functional/Android.bp b/automotive/evs/1.0/vts/functional/Android.bp
index 555ff5b..6ac2458 100644
--- a/automotive/evs/1.0/vts/functional/Android.bp
+++ b/automotive/evs/1.0/vts/functional/Android.bp
@@ -15,7 +15,7 @@
 //
 
 cc_test {
-    name: "VtsHalEvsV1_0Target",
+    name: "VtsHalEvsV1_0TargetTest",
 
     srcs: [
         "VtsHalEvsV1_0TargetTest.cpp",
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp
index 3441a25..bdc44ef 100644
--- a/automotive/vehicle/2.0/Android.bp
+++ b/automotive/vehicle/2.0/Android.bp
@@ -17,6 +17,8 @@
     types: [
         "DiagnosticFloatSensorIndex",
         "DiagnosticIntegerSensorIndex",
+        "EvConnectorType",
+        "FuelType",
         "Obd2CommonIgnitionMonitors",
         "Obd2CompressionIgnitionMonitors",
         "Obd2FuelSystemStatus",
@@ -40,26 +42,12 @@
         "VehicleAreaSeat",
         "VehicleAreaWindow",
         "VehicleAreaZone",
-        "VehicleAudioContextFlag",
-        "VehicleAudioExtFocusFlag",
-        "VehicleAudioFocusIndex",
-        "VehicleAudioFocusRequest",
-        "VehicleAudioFocusState",
-        "VehicleAudioHwVariantConfigFlag",
-        "VehicleAudioRoutingPolicyIndex",
-        "VehicleAudioStream",
-        "VehicleAudioStreamFlag",
-        "VehicleAudioVolumeCapabilityFlag",
-        "VehicleAudioVolumeIndex",
-        "VehicleAudioVolumeLimitIndex",
-        "VehicleAudioVolumeState",
         "VehicleDisplay",
         "VehicleDrivingStatus",
         "VehicleGear",
         "VehicleHvacFanDirection",
         "VehicleHwKeyInputAction",
         "VehicleIgnitionState",
-        "VehicleInstrumentClusterType",
         "VehiclePropConfig",
         "VehiclePropValue",
         "VehicleProperty",
@@ -67,6 +55,7 @@
         "VehiclePropertyChangeMode",
         "VehiclePropertyGroup",
         "VehiclePropertyOperation",
+        "VehiclePropertyStatus",
         "VehiclePropertyType",
         "VehicleRadioConstants",
         "VehicleTurnSignal",
@@ -77,6 +66,7 @@
         "VmsMessageWithLayerAndPublisherIdIntegerValuesIndex",
         "VmsMessageWithLayerIntegerValuesIndex",
         "VmsOfferingMessageIntegerValuesIndex",
+        "VmsPublisherInformationIntegerValuesIndex",
         "VmsSubscriptionsStateIntegerValuesIndex",
         "Wheel",
     ],
diff --git a/automotive/vehicle/2.0/Android.mk b/automotive/vehicle/2.0/Android.mk
deleted file mode 100644
index a731d6d..0000000
--- a/automotive/vehicle/2.0/Android.mk
+++ /dev/null
@@ -1,1282 +0,0 @@
-# This file is autogenerated by hidl-gen. Do not edit manually.
-
-LOCAL_PATH := $(call my-dir)
-
-################################################################################
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.automotive.vehicle-V2.0-java-static
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-
-intermediates := $(call local-generated-sources-dir, COMMON)
-
-HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android.hidl.base-V1.0-java-static \
-
-
-#
-# Build types.hal (DiagnosticFloatSensorIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/DiagnosticFloatSensorIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.DiagnosticFloatSensorIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (DiagnosticIntegerSensorIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/DiagnosticIntegerSensorIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.DiagnosticIntegerSensorIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (Obd2CommonIgnitionMonitors)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2CommonIgnitionMonitors.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.Obd2CommonIgnitionMonitors
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (Obd2CompressionIgnitionMonitors)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2CompressionIgnitionMonitors.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.Obd2CompressionIgnitionMonitors
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (Obd2FuelSystemStatus)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2FuelSystemStatus.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.Obd2FuelSystemStatus
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (Obd2FuelType)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2FuelType.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.Obd2FuelType
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (Obd2IgnitionMonitorKind)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2IgnitionMonitorKind.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.Obd2IgnitionMonitorKind
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (Obd2SecondaryAirStatus)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2SecondaryAirStatus.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.Obd2SecondaryAirStatus
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (Obd2SparkIgnitionMonitors)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Obd2SparkIgnitionMonitors.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.Obd2SparkIgnitionMonitors
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (StatusCode)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/StatusCode.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.StatusCode
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (SubscribeFlags)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/SubscribeFlags.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.SubscribeFlags
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (SubscribeOptions)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/SubscribeOptions.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.SubscribeOptions
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleApPowerBootupReason)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerBootupReason.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleApPowerBootupReason
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleApPowerSetState)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerSetState.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleApPowerSetState
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleApPowerState)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerState.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleApPowerState
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleApPowerStateConfigFlag)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateConfigFlag.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateConfigFlag
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleApPowerStateIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleApPowerStateShutdownParam)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleApPowerStateShutdownParam.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleApPowerStateShutdownParam
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleArea)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleArea.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleArea
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAreaConfig)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaConfig.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAreaConfig
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAreaDoor)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaDoor.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAreaDoor
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAreaMirror)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaMirror.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAreaMirror
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAreaSeat)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaSeat.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAreaSeat
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAreaWindow)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaWindow.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAreaWindow
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAreaZone)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAreaZone.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAreaZone
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioContextFlag)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioContextFlag.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioContextFlag
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioExtFocusFlag)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioExtFocusFlag.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioExtFocusFlag
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioFocusIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioFocusRequest)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusRequest.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusRequest
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioFocusState)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioFocusState.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioFocusState
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioHwVariantConfigFlag)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioHwVariantConfigFlag.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioHwVariantConfigFlag
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioRoutingPolicyIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioRoutingPolicyIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioRoutingPolicyIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioStream)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioStream.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioStream
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioStreamFlag)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioStreamFlag.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioStreamFlag
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioVolumeCapabilityFlag)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeCapabilityFlag.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeCapabilityFlag
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioVolumeIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioVolumeLimitIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeLimitIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeLimitIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleAudioVolumeState)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleAudioVolumeState.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleAudioVolumeState
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleDisplay)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleDisplay.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleDisplay
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleDrivingStatus)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleDrivingStatus.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleDrivingStatus
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleGear)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleGear.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleGear
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleHvacFanDirection)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleHvacFanDirection.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleHvacFanDirection
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleHwKeyInputAction)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleHwKeyInputAction.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleHwKeyInputAction
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleIgnitionState)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleIgnitionState.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleIgnitionState
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleInstrumentClusterType)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleInstrumentClusterType.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleInstrumentClusterType
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehiclePropConfig)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropConfig.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehiclePropConfig
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehiclePropValue)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropValue.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehiclePropValue
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleProperty)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleProperty.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleProperty
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehiclePropertyAccess)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyAccess.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehiclePropertyAccess
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehiclePropertyChangeMode)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyChangeMode.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehiclePropertyChangeMode
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehiclePropertyGroup)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyGroup.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehiclePropertyGroup
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehiclePropertyOperation)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyOperation.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehiclePropertyOperation
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehiclePropertyType)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehiclePropertyType.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehiclePropertyType
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleRadioConstants)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleRadioConstants.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleRadioConstants
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleTurnSignal)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleTurnSignal.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleTurnSignal
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VehicleUnit)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VehicleUnit.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VehicleUnit
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VmsAvailabilityStateIntegerValuesIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsAvailabilityStateIntegerValuesIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsAvailabilityStateIntegerValuesIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VmsBaseMessageIntegerValuesIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsBaseMessageIntegerValuesIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsBaseMessageIntegerValuesIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VmsMessageType)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageType.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsMessageType
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VmsMessageWithLayerAndPublisherIdIntegerValuesIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsMessageWithLayerAndPublisherIdIntegerValuesIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VmsMessageWithLayerIntegerValuesIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageWithLayerIntegerValuesIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsMessageWithLayerIntegerValuesIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VmsOfferingMessageIntegerValuesIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsOfferingMessageIntegerValuesIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsOfferingMessageIntegerValuesIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VmsSubscriptionsStateIntegerValuesIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsSubscriptionsStateIntegerValuesIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsSubscriptionsStateIntegerValuesIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (Wheel)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Wheel.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.Wheel
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build IVehicle.hal
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/IVehicle.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicle.hal
-$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/IVehicleCallback.hal
-$(GEN): $(LOCAL_PATH)/IVehicleCallback.hal
-$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
-$(GEN): $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::IVehicle
-
-$(GEN): $(LOCAL_PATH)/IVehicle.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build IVehicleCallback.hal
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/IVehicleCallback.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IVehicleCallback.hal
-$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/types.hal
-$(GEN): $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::IVehicleCallback
-
-$(GEN): $(LOCAL_PATH)/IVehicleCallback.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/automotive/vehicle/2.0/IVehicle.hal b/automotive/vehicle/2.0/IVehicle.hal
index d962de0..1b1d391 100644
--- a/automotive/vehicle/2.0/IVehicle.hal
+++ b/automotive/vehicle/2.0/IVehicle.hal
@@ -43,7 +43,7 @@
    * For VehiclePropertyChangeMode::ON_CHANGE properties, it must return the
    * latest available value.
    *
-   * Some properties like AUDIO_VOLUME requires to pass additional data in
+   * Some properties like RADIO_PRESET requires to pass additional data in
    * GET request in VehiclePropValue object.
    *
    * If there is no data available yet, which can happen during initial stage,
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 1690163..774bc4f 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -35,7 +35,7 @@
 }
 
 // Vehicle reference implementation lib
-cc_library_static {
+cc_library {
     name: "android.hardware.automotive.vehicle@2.0-manager-lib",
     vendor: true,
     defaults: ["vhal_v2_0_defaults"],
@@ -46,18 +46,12 @@
         "common/src/VehicleObjectPool.cpp",
         "common/src/VehiclePropertyStore.cpp",
         "common/src/VehicleUtils.cpp",
+        "common/src/VmsUtils.cpp",
     ],
     local_include_dirs: ["common/include/vhal_v2_0"],
     export_include_dirs: ["common/include"],
 }
 
-cc_library_shared {
-    name: "android.hardware.automotive.vehicle@2.0-manager-lib-shared",
-    vendor: true,
-    static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"],
-    export_static_lib_headers: ["android.hardware.automotive.vehicle@2.0-manager-lib"],
-}
-
 // Vehicle default VehicleHAL implementation
 cc_library_static {
     name: "android.hardware.automotive.vehicle@2.0-default-impl-lib",
@@ -93,6 +87,7 @@
         "tests/VehicleHalManager_test.cpp",
         "tests/VehicleObjectPool_test.cpp",
         "tests/VehiclePropConfigIndex_test.cpp",
+        "tests/VmsUtils_test.cpp",
     ],
     header_libs: ["libbase_headers"],
 }
diff --git a/automotive/vehicle/2.0/default/OWNERS b/automotive/vehicle/2.0/default/OWNERS
new file mode 100644
index 0000000..d5d9d4c
--- /dev/null
+++ b/automotive/vehicle/2.0/default/OWNERS
@@ -0,0 +1,3 @@
+egranata@google.com
+pavelm@google.com
+spaik@google.com
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
index 30e249e..c8c89dc 100644
--- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc
@@ -1,4 +1,4 @@
-service vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-service
+service vendor.vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-service
     class hal
     user vehicle_network
     group system inet
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
index 8e9089d..6086c01 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
@@ -49,7 +49,7 @@
     }
 
     void addOrUpdateSubscription(const SubscribeOptions &opts);
-    bool isSubscribed(int32_t propId, int32_t areaId, SubscribeFlags flags);
+    bool isSubscribed(int32_t propId, SubscribeFlags flags);
     std::vector<int32_t> getSubscribedProperties() const;
 
 private:
@@ -87,8 +87,7 @@
     /**
      * Constructs SubscriptionManager
      *
-     * @param onPropertyUnsubscribed - this callback function will be called when there are no
-     *                                    more client subscribed to particular property.
+     * @param onPropertyUnsubscribed - called when no more clients are subscribed to the property.
      */
     SubscriptionManager(const OnPropertyUnsubscribed& onPropertyUnsubscribed)
             : mOnPropertyUnsubscribed(onPropertyUnsubscribed),
@@ -115,9 +114,7 @@
             const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
             SubscribeFlags flags) const;
 
-    std::list<sp<HalClient>> getSubscribedClients(int32_t propId,
-                                                  int32_t area,
-                                                  SubscribeFlags flags) const;
+    std::list<sp<HalClient>> getSubscribedClients(int32_t propId, SubscribeFlags flags) const;
     /**
      * If there are no clients subscribed to given properties than callback function provided
      * in the constructor will be called.
@@ -125,10 +122,9 @@
     void unsubscribe(ClientId clientId, int32_t propId);
 private:
     std::list<sp<HalClient>> getSubscribedClientsLocked(int32_t propId,
-                                                        int32_t area,
                                                         SubscribeFlags flags) const;
 
-    bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts, SubscribeOptions* out);
+    bool updateHalEventSubscriptionLocked(const SubscribeOptions& opts, SubscribeOptions* out);
 
     void addClientToPropMapLocked(int32_t propId, const sp<HalClient>& client);
 
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
index 8203a1e..fd28483 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
@@ -48,17 +48,14 @@
 
     /**
      * Subscribe to HAL property events. This method might be called multiple
-     * times for the same vehicle property to update subscribed areas or sample
-     * rate.
+     * times for the same vehicle property to update sample rate.
      *
      * @param property to subscribe
-     * @param areas a bitwise vehicle areas or 0 for all supported areas
      * @param sampleRate sample rate in Hz for properties that support sample
      *                   rate, e.g. for properties with
      *                   VehiclePropertyChangeMode::CONTINUOUS
      */
     virtual StatusCode subscribe(int32_t property,
-                                 int32_t areas,
                                  float sampleRate) = 0;
 
     /**
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
index 05c649b..359bb6d 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
@@ -191,9 +191,8 @@
     VehiclePropValuePool& operator=(VehiclePropValuePool&) = delete;
 private:
     bool isDisposable(VehiclePropertyType type, size_t vecSize) const {
-        return vecSize > mMaxRecyclableVectorSize ||
-               VehiclePropertyType::STRING == type ||
-               VehiclePropertyType::COMPLEX == type;
+        return vecSize > mMaxRecyclableVectorSize || VehiclePropertyType::STRING == type ||
+               VehiclePropertyType::MIXED == type;
     }
 
     RecyclableType obtainDisposable(VehiclePropertyType valueType,
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
new file mode 100644
index 0000000..9e32bb5
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_VmsUtils_H_
+#define android_hardware_automotive_vehicle_V2_0_VmsUtils_H_
+
+#include <memory>
+#include <string>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace vms {
+
+// VmsUtils are a set of abstractions for creating and parsing Vehicle Property
+// updates to VehicleProperty::VEHICLE_MAP_SERVICE. The format for parsing a
+// VehiclePropValue update with a VMS message is specified in the Vehicle HIDL.
+//
+// This interface is meant for use by HAL clients of VMS; corresponding
+// functionality is also provided by VMS in the embedded car service.
+
+// A VmsLayer is comprised of a type, subtype, and version.
+struct VmsLayer {
+    VmsLayer(int type, int subtype, int version) : type(type), subtype(subtype), version(version) {}
+    int type;
+    int subtype;
+    int version;
+};
+
+struct VmsLayerAndPublisher {
+    VmsLayer layer;
+    int publisher_id;
+};
+
+// A VmsAssociatedLayer is used by subscribers to specify which publisher IDs
+// are acceptable for a given layer.
+struct VmsAssociatedLayer {
+    VmsLayer layer;
+    std::vector<int> publisher_ids;
+};
+
+// A VmsLayerOffering refers to a single layer that can be published, along with
+// its dependencies. Dependencies can be empty.
+struct VmsLayerOffering {
+    VmsLayerOffering(VmsLayer layer, std::vector<VmsLayer> dependencies)
+        : layer(layer), dependencies(dependencies) {}
+    VmsLayerOffering(VmsLayer layer) : layer(layer), dependencies() {}
+    VmsLayer layer;
+    std::vector<VmsLayer> dependencies;
+};
+
+// A VmsSubscriptionsState is delivered in response to a
+// VmsMessageType.SUBSCRIPTIONS_REQUEST or on the first SUBSCRIBE or last
+// UNSUBSCRIBE for a layer. It indicates which layers or associated_layers are
+// currently being subscribed to in the system.
+struct VmsSubscriptionsState {
+    int sequence_number;
+    std::vector<VmsLayer> layers;
+    std::vector<VmsAssociatedLayer> associated_layers;
+};
+
+struct VmsAvailabilityState {
+    int sequence_number;
+    std::vector<VmsAssociatedLayer> associated_layers;
+};
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.SUBSCRIBE, specifying to the VMS service
+// which layer to subscribe to.
+std::unique_ptr<VehiclePropValue> createSubscribeMessage(const VmsLayer& layer);
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.SUBSCRIBE_TO_PUBLISHER, specifying to the VMS service
+// which layer and publisher_id to subscribe to.
+std::unique_ptr<VehiclePropValue> createSubscribeToPublisherMessage(
+    const VmsLayerAndPublisher& layer);
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.UNSUBSCRIBE, specifying to the VMS service
+// which layer to unsubscribe from.
+std::unique_ptr<VehiclePropValue> createUnsubscribeMessage(const VmsLayer& layer);
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER, specifying to the VMS service
+// which layer and publisher_id to unsubscribe from.
+std::unique_ptr<VehiclePropValue> createUnsubscribeToPublisherMessage(
+    const VmsLayerAndPublisher& layer);
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.OFFERING, specifying to the VMS service which layers are being
+// offered and their dependencies, if any.
+std::unique_ptr<VehiclePropValue> createOfferingMessage(
+    const std::vector<VmsLayerOffering>& offering);
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.AVAILABILITY_REQUEST.
+std::unique_ptr<VehiclePropValue> createAvailabilityRequest();
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.AVAILABILITY_REQUEST.
+std::unique_ptr<VehiclePropValue> createSubscriptionsRequest();
+
+// Creates a VehiclePropValue containing a message of type VmsMessageType.DATA.
+// Returns a nullptr if the byte string in bytes is empty.
+//
+// For example, to build a VehiclePropMessage containing a proto, the caller
+// should convert the proto to a byte string using the SerializeToString proto
+// API, then use this inteface to build the VehicleProperty.
+std::unique_ptr<VehiclePropValue> createDataMessage(const std::string& bytes);
+
+// Returns true if the VehiclePropValue pointed to by value contains a valid Vms
+// message, i.e. the VehicleProperty, VehicleArea, and VmsMessageType are all
+// valid. Note: If the VmsMessageType enum is extended, this function will
+// return false for any new message types added.
+bool isValidVmsMessage(const VehiclePropValue& value);
+
+// Returns the message type. Expects that the VehiclePropValue contains a valid
+// Vms message, as verified by isValidVmsMessage.
+VmsMessageType parseMessageType(const VehiclePropValue& value);
+
+// Constructs a string byte array from a message of type VmsMessageType.DATA.
+// Returns an empty string if the message type doesn't match or if the
+// VehiclePropValue does not contain a byte array.
+//
+// A proto message can then be constructed by passing the result of this
+// function to ParseFromString.
+std::string parseData(const VehiclePropValue& value);
+
+// TODO(aditin): Need to implement additional parsing functions per message
+// type.
+
+}  // namespace vms
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_VmsUtils_H_
diff --git a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
index 74f0a5f..a7d5f50 100644
--- a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
@@ -34,23 +34,12 @@
 bool mergeSubscribeOptions(const SubscribeOptions &oldOpts,
                            const SubscribeOptions &newOpts,
                            SubscribeOptions *outResult) {
-
-    int32_t updatedAreas = oldOpts.vehicleAreas;
-    if (updatedAreas != kAllSupportedAreas) {
-        updatedAreas = newOpts.vehicleAreas != kAllSupportedAreas
-            ? updatedAreas | newOpts.vehicleAreas
-            : kAllSupportedAreas;
-    }
-
     float updatedRate = std::max(oldOpts.sampleRate, newOpts.sampleRate);
     SubscribeFlags updatedFlags = SubscribeFlags(oldOpts.flags | newOpts.flags);
 
-    bool updated = updatedRate > oldOpts.sampleRate
-                   || updatedAreas != oldOpts.vehicleAreas
-                   || updatedFlags != oldOpts.flags;
+    bool updated = (updatedRate > oldOpts.sampleRate) || (updatedFlags != oldOpts.flags);
     if (updated) {
         *outResult = oldOpts;
-        outResult->vehicleAreas = updatedAreas;
         outResult->sampleRate = updatedRate;
         outResult->flags = updatedFlags;
     }
@@ -75,15 +64,13 @@
 }
 
 bool HalClient::isSubscribed(int32_t propId,
-                             int32_t areaId,
                              SubscribeFlags flags) {
     auto it = mSubscriptions.find(propId);
     if (it == mSubscriptions.end()) {
         return false;
     }
     const SubscribeOptions& opts = it->second;
-    bool res = (opts.flags & flags)
-           && (opts.vehicleAreas == 0 || areaId == 0 || opts.vehicleAreas & areaId);
+    bool res = (opts.flags & flags);
     return res;
 }
 
@@ -139,8 +126,7 @@
         MuxGuard g(mLock);
         for (const auto& propValue: propValues) {
             VehiclePropValue* v = propValue.get();
-            auto clients = getSubscribedClientsLocked(
-                v->prop, v->areaId, flags);
+            auto clients = getSubscribedClientsLocked(v->prop, flags);
             for (const auto& client : clients) {
                 clientValuesMap[client].push_back(v);
             }
@@ -158,21 +144,21 @@
     return clientValues;
 }
 
-std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients(
-    int32_t propId, int32_t area, SubscribeFlags flags) const {
+std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients(int32_t propId,
+                                                                   SubscribeFlags flags) const {
     MuxGuard g(mLock);
-    return getSubscribedClientsLocked(propId, area, flags);
+    return getSubscribedClientsLocked(propId, flags);
 }
 
 std::list<sp<HalClient>> SubscriptionManager::getSubscribedClientsLocked(
-        int32_t propId, int32_t area, SubscribeFlags flags) const {
+    int32_t propId, SubscribeFlags flags) const {
     std::list<sp<HalClient>> subscribedClients;
 
     sp<HalClientVector> propClients = getClientsForPropertyLocked(propId);
     if (propClients.get() != nullptr) {
         for (size_t i = 0; i < propClients->size(); i++) {
             const auto& client = propClients->itemAt(i);
-            if (client->isSubscribed(propId, area, flags)) {
+            if (client->isSubscribed(propId, flags)) {
                 subscribedClients.push_back(client);
             }
         }
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index ae543bb..1918421 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -142,15 +142,6 @@
             return StatusCode::INVALID_ARG;
         }
 
-        int32_t areas = isGlobalProp(prop) ? 0 : ops.vehicleAreas;
-        if (areas != 0 && ((areas & config->supportedAreas) != areas)) {
-            ALOGE("Failed to subscribe property 0x%x. Requested areas 0x%x are "
-                  "out of supported range of 0x%x", prop, ops.vehicleAreas,
-                  config->supportedAreas);
-            return StatusCode::INVALID_ARG;
-        }
-
-        ops.vehicleAreas = areas;
         ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
     }
 
@@ -164,7 +155,7 @@
     }
 
     for (auto opt : updatedOptions) {
-        mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate);
+        mHal->subscribe(opt.propId, opt.sampleRate);
     }
 
     return StatusCode::OK;
@@ -224,8 +215,8 @@
 void VehicleHalManager::onHalPropertySetError(StatusCode errorCode,
                                               int32_t property,
                                               int32_t areaId) {
-    const auto& clients = mSubscriptionManager.getSubscribedClients(
-            property, 0, SubscribeFlags::HAL_EVENT);
+    const auto& clients =
+        mSubscriptionManager.getSubscribedClients(property, SubscribeFlags::HAL_EVENT);
 
     for (auto client : clients) {
         client->getCallback()->onPropertySetError(errorCode, property, areaId);
@@ -326,8 +317,7 @@
 }
 
 void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) {
-    auto clients = mSubscriptionManager.getSubscribedClients(
-            value.prop, value.areaId, SubscribeFlags::SET_CALL);
+    auto clients = mSubscriptionManager.getSubscribedClients(value.prop, SubscribeFlags::SET_CALL);
     for (auto client : clients) {
         client->getCallback()->onPropertySet(value);
     }
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
index ac1245a..40dd56e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp
@@ -47,6 +47,7 @@
 
     dest->prop = src.prop;
     dest->areaId = src.areaId;
+    dest->status = src.status;
     dest->timestamp = src.timestamp;
     copyVehicleRawValue(&dest->value, src.value);
 
@@ -82,7 +83,7 @@
 }
 
 VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainComplex() {
-    return obtain(VehiclePropertyType::COMPLEX);
+    return obtain(VehiclePropertyType::MIXED);
 }
 
 VehiclePropValuePool::RecyclableType VehiclePropValuePool::obtainRecylable(
@@ -138,18 +139,14 @@
 }
 
 bool VehiclePropValuePool::InternalPool::check(VehiclePropValue::RawValue* v) {
-    return check(&v->int32Values,
-                 (VehiclePropertyType::INT32 == mPropType
-                  || VehiclePropertyType::INT32_VEC == mPropType
-                  || VehiclePropertyType::BOOLEAN == mPropType))
-           && check(&v->floatValues,
-                    (VehiclePropertyType::FLOAT == mPropType
-                     || VehiclePropertyType::FLOAT_VEC == mPropType))
-           && check(&v->int64Values,
-                    VehiclePropertyType::INT64 == mPropType)
-           && check(&v->bytes,
-                    VehiclePropertyType::BYTES == mPropType)
-           && v->stringValue.size() == 0;
+    return check(&v->int32Values, (VehiclePropertyType::INT32 == mPropType ||
+                                   VehiclePropertyType::INT32_VEC == mPropType ||
+                                   VehiclePropertyType::BOOLEAN == mPropType)) &&
+           check(&v->floatValues, (VehiclePropertyType::FLOAT == mPropType ||
+                                   VehiclePropertyType::FLOAT_VEC == mPropType)) &&
+           check(&v->int64Values, (VehiclePropertyType::INT64 == mPropType ||
+                                   VehiclePropertyType::INT64_VEC == mPropType)) &&
+           check(&v->bytes, VehiclePropertyType::BYTES == mPropType) && v->stringValue.size() == 0;
 }
 
 VehiclePropValue* VehiclePropValuePool::InternalPool::createObject() {
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
index 9146fa1..5b6816e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp
@@ -42,13 +42,14 @@
             val->value.floatValues.resize(vecSize);
             break;
         case VehiclePropertyType::INT64:
+        case VehiclePropertyType::INT64_VEC:
             val->value.int64Values.resize(vecSize);
             break;
         case VehiclePropertyType::BYTES:
             val->value.bytes.resize(vecSize);
             break;
         case VehiclePropertyType::STRING:
-        case VehiclePropertyType::COMPLEX:
+        case VehiclePropertyType::MIXED:
             break; // Valid, but nothing to do.
         default:
             ALOGE("createVehiclePropValue: unknown type: %d", type);
@@ -68,6 +69,7 @@
         case VehiclePropertyType::FLOAT_VEC:
             return value.floatValues.size();
         case VehiclePropertyType::INT64:
+        case VehiclePropertyType::INT64_VEC:
             return value.int64Values.size();
         case VehiclePropertyType::BYTES:
             return value.bytes.size();
@@ -112,6 +114,7 @@
 void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src) {
     dest->prop = src.prop;
     dest->areaId = src.areaId;
+    dest->status = src.status;
     dest->timestamp = src.timestamp;
     shallowCopyHidlVec(&dest->value.int32Values, src.value.int32Values);
     shallowCopyHidlVec(&dest->value.int64Values, src.value.int64Values);
diff --git a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
new file mode 100644
index 0000000..abf425f
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VmsUtils.h"
+
+#include <common/include/vhal_v2_0/VehicleUtils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace vms {
+
+static constexpr int kMessageIndex = toInt(VmsBaseMessageIntegerValuesIndex::MESSAGE_TYPE);
+static constexpr int kMessageTypeSize = 1;
+static constexpr int kLayerNumberSize = 1;
+static constexpr int kLayerSize = 3;
+static constexpr int kLayerAndPublisherSize = 4;
+
+// TODO(aditin): We should extend the VmsMessageType enum to include a first and
+// last, which would prevent breakages in this API. However, for all of the
+// functions in this module, we only need to guarantee that the message type is
+// between SUBSCRIBE and DATA.
+static constexpr int kFirstMessageType = toInt(VmsMessageType::SUBSCRIBE);
+static constexpr int kLastMessageType = toInt(VmsMessageType::DATA);
+
+std::unique_ptr<VehiclePropValue> createBaseVmsMessage(size_t message_size) {
+    auto result = createVehiclePropValue(VehiclePropertyType::INT32, message_size);
+    result->prop = toInt(VehicleProperty::VEHICLE_MAP_SERVICE);
+    result->areaId = toInt(VehicleArea::GLOBAL);
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createSubscribeMessage(const VmsLayer& layer) {
+    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerSize);
+    result->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIBE), layer.type,
+                                                  layer.subtype, layer.version};
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createSubscribeToPublisherMessage(
+    const VmsLayerAndPublisher& layer_publisher) {
+    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerAndPublisherSize);
+    result->value.int32Values = hidl_vec<int32_t>{
+        toInt(VmsMessageType::SUBSCRIBE_TO_PUBLISHER), layer_publisher.layer.type,
+        layer_publisher.layer.subtype, layer_publisher.layer.version, layer_publisher.publisher_id};
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createUnsubscribeMessage(const VmsLayer& layer) {
+    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerSize);
+    result->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::UNSUBSCRIBE), layer.type,
+                                                  layer.subtype, layer.version};
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createUnsubscribeToPublisherMessage(
+    const VmsLayerAndPublisher& layer_publisher) {
+    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerAndPublisherSize);
+    result->value.int32Values = hidl_vec<int32_t>{
+        toInt(VmsMessageType::UNSUBSCRIBE_TO_PUBLISHER), layer_publisher.layer.type,
+        layer_publisher.layer.subtype, layer_publisher.layer.version, layer_publisher.publisher_id};
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createOfferingMessage(
+    const std::vector<VmsLayerOffering>& offering) {
+    int message_size = kMessageTypeSize + kLayerNumberSize;
+    for (const auto& offer : offering) {
+        message_size += kLayerNumberSize + (1 + offer.dependencies.size()) * kLayerSize;
+    }
+    auto result = createBaseVmsMessage(message_size);
+
+    std::vector<int32_t> offers = {toInt(VmsMessageType::OFFERING),
+                                   static_cast<int>(offering.size())};
+    for (const auto& offer : offering) {
+        std::vector<int32_t> layer_vector = {offer.layer.type, offer.layer.subtype,
+                                             offer.layer.version,
+                                             static_cast<int32_t>(offer.dependencies.size())};
+        for (const auto& dependency : offer.dependencies) {
+            std::vector<int32_t> dependency_layer = {dependency.type, dependency.subtype,
+                                                     dependency.version};
+            layer_vector.insert(layer_vector.end(), dependency_layer.begin(),
+                                dependency_layer.end());
+        }
+        offers.insert(offers.end(), layer_vector.begin(), layer_vector.end());
+    }
+    result->value.int32Values = offers;
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createAvailabilityRequest() {
+    auto result = createBaseVmsMessage(kMessageTypeSize);
+    result->value.int32Values = hidl_vec<int32_t>{
+        toInt(VmsMessageType::AVAILABILITY_REQUEST),
+    };
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createSubscriptionsRequest() {
+    auto result = createBaseVmsMessage(kMessageTypeSize);
+    result->value.int32Values = hidl_vec<int32_t>{
+        toInt(VmsMessageType::SUBSCRIPTIONS_REQUEST),
+    };
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createDataMessage(const std::string& bytes) {
+    auto result = createBaseVmsMessage(kMessageTypeSize);
+    result->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::DATA)};
+    result->value.bytes = std::vector<uint8_t>(bytes.begin(), bytes.end());
+    return result;
+}
+
+bool verifyPropertyAndArea(const VehiclePropValue& value) {
+    return (value.prop == toInt(VehicleProperty::VEHICLE_MAP_SERVICE) &&
+            value.areaId == toInt(VehicleArea::GLOBAL));
+}
+
+bool verifyMessageType(const VehiclePropValue& value) {
+    return (value.value.int32Values.size() > 0 &&
+            value.value.int32Values[kMessageIndex] >= kFirstMessageType &&
+            value.value.int32Values[kMessageIndex] <= kLastMessageType);
+}
+
+bool isValidVmsMessage(const VehiclePropValue& value) {
+    return (verifyPropertyAndArea(value) && verifyMessageType(value));
+}
+
+VmsMessageType parseMessageType(const VehiclePropValue& value) {
+    return static_cast<VmsMessageType>(value.value.int32Values[kMessageIndex]);
+}
+
+std::string parseData(const VehiclePropValue& value) {
+    if (isValidVmsMessage(value) && parseMessageType(value) == VmsMessageType::DATA &&
+        value.value.bytes.size() > 0) {
+        return std::string(value.value.bytes.begin(), value.value.bytes.end());
+    } else {
+        return std::string();
+    }
+}
+
+}  // namespace vms
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 08d3d79..7938b73 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -54,10 +54,8 @@
  *   floatValues[1] - dispersion defines min and max range relative to initial value
  *   floatValues[2] - increment, with every timer tick the value will be incremented by this amount
  */
-const int32_t kGenerateFakeDataControllingProperty = 0x0666
-        | VehiclePropertyGroup::VENDOR
-        | VehicleArea::GLOBAL
-        | VehiclePropertyType::COMPLEX;
+const int32_t kGenerateFakeDataControllingProperty =
+    0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
 
 const int32_t kHvacPowerProperties[] = {
     toInt(VehicleProperty::HVAC_FAN_SPEED),
@@ -78,6 +76,38 @@
 const ConfigDeclaration kVehicleProperties[]{
     {.config =
          {
+             .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::STATIC,
+         },
+     .initialValue = {.floatValues = {15000}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::INFO_FUEL_TYPE),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::STATIC,
+         },
+     .initialValue = {.int32Values = {1}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::STATIC,
+         },
+     .initialValue = {.floatValues = {150000}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::INFO_EV_CONNECTOR_TYPE),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::STATIC,
+         },
+     .initialValue = {.int32Values = {1}}},
+
+    {.config =
+         {
              .prop = toInt(VehicleProperty::INFO_MAKE),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::STATIC,
@@ -89,7 +119,7 @@
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
              .minSampleRate = 1.0f,
-             .maxSampleRate = 1000.0f,
+             .maxSampleRate = 10.0f,
          },
      .initialValue = {.floatValues = {0.0f}}},
 
@@ -101,6 +131,14 @@
          },
      .initialValue = {.floatValues = {0.0f}}},
 
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::ENGINE_ON),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+         },
+     .initialValue = {.int32Values = {0}}},
+
     {
         .config =
             {
@@ -108,13 +146,61 @@
                 .access = VehiclePropertyAccess::READ,
                 .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
                 .minSampleRate = 1.0f,
-                .maxSampleRate = 1000.0f,
+                .maxSampleRate = 10.0f,
             },
         .initialValue = {.floatValues = {0.0f}},
     },
 
     {.config =
          {
+             .prop = toInt(VehicleProperty::FUEL_LEVEL),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+         },
+     .initialValue = {.floatValues = {15000}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+         },
+     .initialValue = {.int32Values = {0}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+         },
+     .initialValue = {.floatValues = {150000}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+         },
+     .initialValue = {.int32Values = {0}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+         },
+     .initialValue = {.int32Values = {0}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+         },
+     .initialValue = {.floatValues = {0}}},
+
+    {.config =
+         {
              .prop = toInt(VehicleProperty::CURRENT_GEAR),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -139,10 +225,19 @@
 
     {.config =
          {
+             .prop = toInt(VehicleProperty::HW_KEY_INPUT),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+         },
+     .initialValue = {.int32Values = {0, 0, 0}}},
+
+    {.config =
+         {
              .prop = toInt(VehicleProperty::HVAC_POWER_ON),
              .access = VehiclePropertyAccess::READ_WRITE,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .supportedAreas = toInt(VehicleAreaZone::ROW_1),
+             .areaConfigs = {VehicleAreaConfig{
+                 .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT)}},
              // TODO(bryaneyler): Ideally, this is generated dynamically from
              // kHvacPowerProperties.
              .configString = "0x12400500,0x12400501"  // HVAC_FAN_SPEED,HVAC_FAN_DIRECTION
@@ -153,51 +248,52 @@
         .config = {.prop = toInt(VehicleProperty::HVAC_DEFROSTER),
                    .access = VehiclePropertyAccess::READ_WRITE,
                    .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                   .supportedAreas =
-                       VehicleAreaWindow::FRONT_WINDSHIELD | VehicleAreaWindow::REAR_WINDSHIELD},
+                   .areaConfigs =
+                       {VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
+                        VehicleAreaConfig{.areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
         .initialValue = {.int32Values = {0}}  // Will be used for all areas.
     },
 
     {.config = {.prop = toInt(VehicleProperty::HVAC_RECIRC_ON),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .supportedAreas = toInt(VehicleAreaZone::ROW_1)},
+                .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT)}}},
      .initialValue = {.int32Values = {1}}},
 
     {.config = {.prop = toInt(VehicleProperty::HVAC_AC_ON),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .supportedAreas = toInt(VehicleAreaZone::ROW_1)},
+                .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT)}}},
      .initialValue = {.int32Values = {1}}},
 
     {.config = {.prop = toInt(VehicleProperty::HVAC_AUTO_ON),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .supportedAreas = toInt(VehicleAreaZone::ROW_1)},
+                .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT)}}},
      .initialValue = {.int32Values = {1}}},
 
     {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .supportedAreas = toInt(VehicleAreaZone::ROW_1),
-                .areaConfigs = {VehicleAreaConfig{.areaId = toInt(VehicleAreaZone::ROW_1),
-                                                  .minInt32Value = 1,
-                                                  .maxInt32Value = 7}}},
+                .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
+                    .minInt32Value = 1,
+                    .maxInt32Value = 7}}},
      .initialValue = {.int32Values = {3}}},
 
-    {.config =
-         {
-             .prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
-             .access = VehiclePropertyAccess::READ_WRITE,
-             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-             .supportedAreas = toInt(VehicleAreaZone::ROW_1),
-         },
+    {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION),
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                .areaConfigs = {VehicleAreaConfig{
+                    .areaId = (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT)}}},
      .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}},
 
     {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-                .supportedAreas = VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT,
                 .areaConfigs = {VehicleAreaConfig{
                                     .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
                                     .minFloatValue = 16,
@@ -246,16 +342,6 @@
          },
      .initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
 
-    {
-        .config =
-            {
-                .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
-                .access = VehiclePropertyAccess::READ,
-                .changeMode = VehiclePropertyChangeMode::STATIC,
-            },
-        .initialValue = {.floatValues = {123000.0f}}  // In Milliliters
-    },
-
     {.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -272,6 +358,14 @@
 
     {.config =
          {
+             .prop = toInt(VehicleProperty::ENGINE_OIL_LEVEL),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+         },
+     .initialValue = {.int32Values = {toInt(VehicleOilLevel::NORMAL)}}},
+
+    {.config =
+         {
              .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
@@ -297,17 +391,16 @@
          },
      .initialValue = {.int32Values = {1}}},
 
-    {
-        .config =
-            {
-                .prop = WHEEL_TICK,
-                .access = VehiclePropertyAccess::READ,
-                .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
-                .configArray = {ALL_WHEELS, 50000, 50000, 50000, 50000},
-                .minSampleRate = 1.0f,
-                .maxSampleRate = 100.0f,
-            },
-    },
+    {.config =
+         {
+             .prop = WHEEL_TICK,
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+             .configArray = {ALL_WHEELS, 50000, 50000, 50000, 50000},
+             .minSampleRate = 1.0f,
+             .maxSampleRate = 10.0f,
+         },
+     .initialValue = {.int64Values = {0, 100000, 200000, 300000, 400000}}},
 
     {
         .config =
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 6bc0522..5118b18 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -138,8 +138,9 @@
             return status;
         }
     } else if (mHvacPowerProps.count(propValue.prop)) {
-        auto hvacPowerOn = mPropStore->readValueOrNull(toInt(VehicleProperty::HVAC_POWER_ON),
-                                                      toInt(VehicleAreaZone::ROW_1));
+        auto hvacPowerOn = mPropStore->readValueOrNull(
+            toInt(VehicleProperty::HVAC_POWER_ON),
+            (VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT));
 
         if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
                 && hvacPowerOn->value.int32Values[0] == 0) {
@@ -177,7 +178,7 @@
 void EmulatedVehicleHal::onCreate() {
     for (auto& it : kVehicleProperties) {
         VehiclePropConfig cfg = it.config;
-        int32_t supportedAreas = cfg.supportedAreas;
+        int32_t numAreas = cfg.areaConfigs.size();
 
         if (isDiagnosticProperty(cfg)) {
             // do not write an initial empty value for the diagnostic properties
@@ -185,22 +186,26 @@
             continue;
         }
 
-        //  A global property will have supportedAreas = 0
+        // A global property will have only a single area
         if (isGlobalProp(cfg.prop)) {
-            supportedAreas = 0;
+            numAreas = 1;
         }
 
-        // This loop is a do-while so it executes at least once to handle global properties
-        do {
-            int32_t curArea = supportedAreas;
-            supportedAreas &= supportedAreas - 1;  // Clear the right-most bit of supportedAreas.
-            curArea ^= supportedAreas;  // Set curArea to the previously cleared bit.
+        for (int i = 0; i < numAreas; i++) {
+            int32_t curArea;
+
+            if (isGlobalProp(cfg.prop)) {
+                curArea = 0;
+            } else {
+                curArea = cfg.areaConfigs[i].areaId;
+            }
 
             // Create a separate instance for each individual zone
             VehiclePropValue prop = {
                 .prop = cfg.prop,
                 .areaId = curArea,
             };
+
             if (it.initialAreaValues.size() > 0) {
                 auto valueForAreaIt = it.initialAreaValues.find(curArea);
                 if (valueForAreaIt != it.initialAreaValues.end()) {
@@ -213,8 +218,7 @@
                 prop.value = it.initialValue;
             }
             mPropStore->writeValue(prop);
-
-        } while (supportedAreas != 0);
+        }
     }
     initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
     initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
@@ -246,8 +250,7 @@
     }
 }
 
-StatusCode EmulatedVehicleHal::subscribe(int32_t property, int32_t,
-                                        float sampleRate) {
+StatusCode EmulatedVehicleHal::subscribe(int32_t property, float sampleRate) {
     ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
 
     if (isContinuousProperty(property)) {
@@ -360,6 +363,7 @@
         updatedPropValue->prop = propId;
         updatedPropValue->areaId = 0;  // Add area support if necessary.
         updatedPropValue->timestamp = elapsedRealtimeNano();
+        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
         mPropStore->writeValue(*updatedPropValue);
         auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode;
         if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
@@ -389,7 +393,7 @@
 }
 
 void EmulatedVehicleHal::initObd2LiveFrame(const VehiclePropConfig& propConfig) {
-    auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::COMPLEX, 0);
+    auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
     auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
                                             static_cast<size_t>(propConfig.configArray[1]));
     sensorStore->fillPropValue("", liveObd2Frame.get());
@@ -406,7 +410,7 @@
                                                   "P0102"
                                                   "P0123"};
     for (auto&& dtc : sampleDtcs) {
-        auto freezeFrame = createVehiclePropValue(VehiclePropertyType::COMPLEX, 0);
+        auto freezeFrame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
         sensorStore->fillPropValue(dtc, freezeFrame.get());
         freezeFrame->prop = OBD2_FREEZE_FRAME;
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index 99d7edb..62fc126 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -53,7 +53,7 @@
     VehiclePropValuePtr get(const VehiclePropValue& requestedPropValue,
                             StatusCode* outStatus) override;
     StatusCode set(const VehiclePropValue& propValue) override;
-    StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override;
+    StatusCode subscribe(int32_t property, float sampleRate) override;
     StatusCode unsubscribe(int32_t property) override;
 
     //  Methods from EmulatedVehicleHalIface
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
index 38cb743..bf7be09 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
@@ -138,6 +138,7 @@
     VehiclePropValue val = {
         .prop = protoVal.prop(),
         .areaId = protoVal.area_id(),
+        .status = (VehiclePropertyStatus)protoVal.status(),
         .timestamp = elapsedRealtimeNano(),
     };
 
@@ -234,10 +235,6 @@
     protoCfg->set_change_mode(toInt(cfg.changeMode));
     protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
 
-    if (!isGlobalProp(cfg.prop)) {
-        protoCfg->set_supported_areas(cfg.supportedAreas);
-    }
-
     for (auto& configElement : cfg.configArray) {
         protoCfg->add_config_array(configElement);
     }
@@ -251,9 +248,10 @@
         case VehiclePropertyType::STRING:
         case VehiclePropertyType::BOOLEAN:
         case VehiclePropertyType::INT32_VEC:
+        case VehiclePropertyType::INT64_VEC:
         case VehiclePropertyType::FLOAT_VEC:
         case VehiclePropertyType::BYTES:
-        case VehiclePropertyType::COMPLEX:
+        case VehiclePropertyType::MIXED:
             // Do nothing.  These types don't have min/max values
             break;
         case VehiclePropertyType::INT64:
@@ -291,6 +289,7 @@
     protoVal->set_prop(val->prop);
     protoVal->set_value_type(toInt(getPropType(val->prop)));
     protoVal->set_timestamp(val->timestamp);
+    protoVal->set_status((emulator::VehiclePropStatus)(val->status));
     protoVal->set_area_id(val->areaId);
 
     // Copy value data if it is set.
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
index ec35200..6754843 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/Android.bp
@@ -23,5 +23,9 @@
     strip: {
         keep_symbols: true,
     },
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     srcs: ["VehicleHalProto.proto"]
 }
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
index 86433f5..2ef64fb 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
@@ -46,6 +46,12 @@
     ERROR_INVALID_OPERATION             = 8;
 }
 
+enum VehiclePropStatus {
+    AVAILABLE                           = 0;
+    UNAVAILABLE                         = 1;
+    ERROR                               = 2;
+}
+
 message VehicleAreaConfig {
     required int32  area_id             = 1;
     optional sint32 min_int32_value     = 2;
@@ -61,7 +67,7 @@
     optional int32             access              = 2;
     optional int32             change_mode         = 3;
     optional int32             value_type          = 4;
-    optional int32             supported_areas     = 5;
+    optional int32             supported_areas     = 5;     // Deprecated - DO NOT USE
     repeated VehicleAreaConfig area_configs        = 6;
     optional int32             config_flags        = 7;
     repeated int32             config_array        = 8;
@@ -75,6 +81,7 @@
     required int32  prop                = 1;
     optional int32  value_type          = 2;
     optional int64  timestamp           = 3;    // required for valid data from HAL, skipped for set
+    optional VehiclePropStatus  status  = 10;   // required for valid data from HAL, skipped for set
 
     // values
     optional int32  area_id             = 4;
diff --git a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
index 5688dd6..4865e9e 100644
--- a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
@@ -51,11 +51,7 @@
     }
 
     hidl_vec<SubscribeOptions> subscrToProp1 = {
-        SubscribeOptions {
-            .propId = PROP1,
-            .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT),
-            .flags = SubscribeFlags::HAL_EVENT
-        },
+        SubscribeOptions{.propId = PROP1, .flags = SubscribeFlags::HAL_EVENT},
     };
 
     hidl_vec<SubscribeOptions> subscrToProp2 = {
@@ -66,15 +62,8 @@
     };
 
     hidl_vec<SubscribeOptions> subscrToProp1and2 = {
-        SubscribeOptions {
-            .propId = PROP1,
-            .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT),
-            .flags = SubscribeFlags::HAL_EVENT
-        },
-        SubscribeOptions {
-            .propId = PROP2,
-            .flags = SubscribeFlags::HAL_EVENT
-        },
+        SubscribeOptions{.propId = PROP1, .flags = SubscribeFlags::HAL_EVENT},
+        SubscribeOptions{.propId = PROP2, .flags = SubscribeFlags::HAL_EVENT},
     };
 
     static std::list<sp<IVehicleCallback>> extractCallbacks(
@@ -87,14 +76,11 @@
     }
 
     std::list<sp<HalClient>> clientsToProp1() {
-        return manager.getSubscribedClients(PROP1,
-                                            toInt(VehicleAreaZone::ROW_1_LEFT),
-                                            SubscribeFlags::DEFAULT);
+        return manager.getSubscribedClients(PROP1, SubscribeFlags::DEFAULT);
     }
 
     std::list<sp<HalClient>> clientsToProp2() {
-        return manager.getSubscribedClients(PROP2, 0,
-                                            SubscribeFlags::DEFAULT);
+        return manager.getSubscribedClients(PROP2, SubscribeFlags::DEFAULT);
     }
 
     void onPropertyUnsubscribed(int propertyId) {
@@ -126,7 +112,6 @@
 
     auto clients = manager.getSubscribedClients(
             PROP1,
-            toInt(VehicleAreaZone::ROW_1_LEFT),
             SubscribeFlags::HAL_EVENT);
 
     ASSERT_ALL_EXISTS({cb1, cb2}, extractCallbacks(clients));
@@ -137,24 +122,14 @@
     ASSERT_EQ(StatusCode::OK,
               manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions));
 
-    // Wrong zone
-    auto clients = manager.getSubscribedClients(
-            PROP1,
-            toInt(VehicleAreaZone::ROW_2_LEFT),
-            SubscribeFlags::HAL_EVENT);
-    ASSERT_TRUE(clients.empty());
-
     // Wrong prop
-    clients = manager.getSubscribedClients(
-            toInt(VehicleProperty::AP_POWER_BOOTUP_REASON),
-            toInt(VehicleAreaZone::ROW_1_LEFT),
-            SubscribeFlags::HAL_EVENT);
+    auto clients = manager.getSubscribedClients(toInt(VehicleProperty::AP_POWER_BOOTUP_REASON),
+                                                SubscribeFlags::HAL_EVENT);
     ASSERT_TRUE(clients.empty());
 
     // Wrong flag
     clients = manager.getSubscribedClients(
             PROP1,
-            toInt(VehicleAreaZone::ROW_1_LEFT),
             SubscribeFlags::SET_CALL);
     ASSERT_TRUE(clients.empty());
 }
@@ -166,7 +141,6 @@
 
     auto clients = manager.getSubscribedClients(
             PROP1,
-            toInt(VehicleAreaZone::ROW_1_LEFT),
             SubscribeFlags::DEFAULT);
     ASSERT_EQ((size_t) 1, clients.size());
     ASSERT_EQ(cb1, clients.front()->getCallback());
@@ -176,18 +150,15 @@
     ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(1, cb1, {
         SubscribeOptions {
                 .propId = PROP1,
-                .vehicleAreas = toInt(VehicleAreaZone::ROW_2),
                 .flags = SubscribeFlags::DEFAULT
             }
         }, &updatedOptions));
 
     clients = manager.getSubscribedClients(PROP1,
-                                           toInt(VehicleAreaZone::ROW_1_LEFT),
                                            SubscribeFlags::DEFAULT);
     ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
 
     clients = manager.getSubscribedClients(PROP1,
-                                           toInt(VehicleAreaZone::ROW_2),
                                            SubscribeFlags::DEFAULT);
     ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
 }
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
index 4864d5d..5b195db 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
@@ -106,7 +106,6 @@
     }
 
     StatusCode subscribe(int32_t /* property */,
-                         int32_t /* areas */,
                          float /* sampleRate */) override {
         return StatusCode::OK;
     }
@@ -286,6 +285,7 @@
 
     cb->reset();
     VehiclePropValue actualValue(*subscribedValue.get());
+    actualValue.status = VehiclePropertyStatus::AVAILABLE;
     hal->sendPropEvent(std::move(subscribedValue));
 
     ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: "
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
index 2a06417..3cabcf2 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
@@ -29,10 +29,8 @@
 namespace vehicle {
 namespace V2_0 {
 
-constexpr int32_t kCustomComplexProperty = 0xbeef
-        | VehiclePropertyGroup::VENDOR
-        | VehiclePropertyType::COMPLEX
-        | VehicleArea::GLOBAL;
+constexpr int32_t kCustomComplexProperty =
+    0xbeef | VehiclePropertyGroup::VENDOR | VehiclePropertyType::MIXED | VehicleArea::GLOBAL;
 
 const VehiclePropConfig kVehicleProperties[] = {
     {
@@ -46,8 +44,6 @@
         .prop = toInt(VehicleProperty::HVAC_FAN_SPEED),
         .access = VehiclePropertyAccess::READ_WRITE,
         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
-        .supportedAreas = static_cast<int32_t>(
-            VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
         .areaConfigs = {
             VehicleAreaConfig {
                 .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
@@ -66,8 +62,6 @@
         .prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE),
         .access = VehiclePropertyAccess::WRITE,
         .changeMode = VehiclePropertyChangeMode::ON_SET,
-        .supportedAreas = static_cast<int32_t>(
-            VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT),
         .areaConfigs = {
             VehicleAreaConfig {
                 .areaId = toInt(VehicleAreaZone::ROW_1_LEFT),
diff --git a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
new file mode 100644
index 0000000..c102ce8
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <gtest/gtest.h>
+
+#include "VehicleHalTestUtils.h"
+#include "vhal_v2_0/VmsUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace vms {
+
+namespace {
+
+TEST(VmsUtilsTest, subscribeMessage) {
+    VmsLayer layer(1, 0, 2);
+    auto message = createSubscribeMessage(layer);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x4ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::SUBSCRIBE);
+
+    // Layer
+    EXPECT_EQ(message->value.int32Values[1], 1);
+    EXPECT_EQ(message->value.int32Values[2], 0);
+    EXPECT_EQ(message->value.int32Values[3], 2);
+}
+
+TEST(VmsUtilsTest, unsubscribeMessage) {
+    VmsLayer layer(1, 0, 2);
+    auto message = createUnsubscribeMessage(layer);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x4ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::UNSUBSCRIBE);
+
+    // Layer
+    EXPECT_EQ(message->value.int32Values[1], 1);
+    EXPECT_EQ(message->value.int32Values[2], 0);
+    EXPECT_EQ(message->value.int32Values[3], 2);
+}
+
+TEST(VmsUtilsTest, singleOfferingMessage) {
+    std::vector<VmsLayerOffering> offering = {VmsLayerOffering(VmsLayer(1, 0, 2))};
+    auto message = createOfferingMessage(offering);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x6ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::OFFERING);
+
+    // Number of layer offerings
+    EXPECT_EQ(message->value.int32Values[1], 1);
+
+    // Layer
+    EXPECT_EQ(message->value.int32Values[2], 1);
+    EXPECT_EQ(message->value.int32Values[3], 0);
+    EXPECT_EQ(message->value.int32Values[4], 2);
+
+    // Number of dependencies
+    EXPECT_EQ(message->value.int32Values[5], 0);
+}
+
+TEST(VmsUtilsTest, offeringWithDependencies) {
+    VmsLayer layer(1, 0, 2);
+    std::vector<VmsLayer> dependencies = {VmsLayer(2, 0, 2)};
+    std::vector<VmsLayerOffering> offering = {VmsLayerOffering(layer, dependencies)};
+    auto message = createOfferingMessage(offering);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x9ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::OFFERING);
+
+    // Number of layer offerings
+    EXPECT_EQ(message->value.int32Values[1], 1);
+
+    // Layer
+    EXPECT_EQ(message->value.int32Values[2], 1);
+    EXPECT_EQ(message->value.int32Values[3], 0);
+    EXPECT_EQ(message->value.int32Values[4], 2);
+
+    // Number of dependencies
+    EXPECT_EQ(message->value.int32Values[5], 1);
+
+    // Dependency 1
+    EXPECT_EQ(message->value.int32Values[6], 2);
+    EXPECT_EQ(message->value.int32Values[7], 0);
+    EXPECT_EQ(message->value.int32Values[8], 2);
+}
+
+TEST(VmsUtilsTest, availabilityMessage) {
+    auto message = createAvailabilityRequest();
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x1ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::AVAILABILITY_REQUEST);
+}
+
+TEST(VmsUtilsTest, subscriptionsMessage) {
+    auto message = createSubscriptionsRequest();
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x1ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::SUBSCRIPTIONS_REQUEST);
+}
+
+TEST(VmsUtilsTest, dataMessage) {
+    std::string bytes = "aaa";
+    auto message = createDataMessage(bytes);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x1ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::DATA);
+    EXPECT_EQ(message->value.bytes.size(), bytes.size());
+    EXPECT_EQ(memcmp(message->value.bytes.data(), bytes.data(), bytes.size()), 0);
+}
+
+TEST(VmsUtilsTest, emptyMessageInvalid) {
+    VehiclePropValue empty_prop;
+    EXPECT_FALSE(isValidVmsMessage(empty_prop));
+}
+
+TEST(VmsUtilsTest, invalidMessageType) {
+    VmsLayer layer(1, 0, 2);
+    auto message = createSubscribeMessage(layer);
+    message->value.int32Values[0] = 0;
+
+    EXPECT_FALSE(isValidVmsMessage(*message));
+}
+
+TEST(VmsUtilsTest, parseDataMessage) {
+    std::string bytes = "aaa";
+    auto message = createDataMessage(bytes);
+    auto data_str = parseData(*message);
+    ASSERT_FALSE(data_str.empty());
+    EXPECT_EQ(data_str, bytes);
+}
+
+TEST(VmsUtilsTest, parseInvalidDataMessage) {
+    VmsLayer layer(1, 0, 2);
+    auto message = createSubscribeMessage(layer);
+    auto data_str = parseData(*message);
+    EXPECT_TRUE(data_str.empty());
+}
+
+}  // namespace
+
+}  // namespace vms
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 7c08b4a..3001213 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -27,6 +27,7 @@
     INT32          = 0x00400000,
     INT32_VEC      = 0x00410000,
     INT64          = 0x00500000,
+    INT64_VEC      = 0x00510000,
     FLOAT          = 0x00600000,
     FLOAT_VEC      = 0x00610000,
     BYTES          = 0x00700000,
@@ -35,7 +36,7 @@
      * Any combination of scalar or vector types. The exact format must be
      * provided in the description of the property.
      */
-    COMPLEX        = 0x00e00000,
+    MIXED          = 0x00e00000,
 
     MASK           = 0x00ff0000
 };
@@ -148,7 +149,7 @@
         | VehicleArea:GLOBAL),
 
     /**
-     * Fuel capacity of the vehicle
+     * Fuel capacity of the vehicle in milliliters
      *
      * @change_mode VehiclePropertyChangeMode:STATIC
      * @access VehiclePropertyAccess:READ
@@ -161,6 +162,45 @@
         | VehicleArea:GLOBAL),
 
     /**
+     * List of fuels the vehicle may use.  Uses enum FuelType
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     * @unit VehicleUnit:MILLILITERS
+     */
+    INFO_FUEL_TYPE = (
+        0x0105
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:INT32_VEC
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Battery capacity of the vehicle, if EV or hybrid.  This is the nominal
+     * battery capacity when the vehicle is new.
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     * @unit VehicleUnit:WH
+     */
+    INFO_EV_BATTERY_CAPACITY = (
+        0x0106
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:FLOAT
+        | VehicleArea:GLOBAL),
+
+    /**
+     * List of connectors this EV may use.  Uses enum EvConnectorType
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     */
+    INFO_EV_CONNECTOR_TYPE = (
+        0x0107
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:INT32_VEC
+        | VehicleArea:GLOBAL),
+
+    /**
      * Current odometer value of the vehicle
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE | VehiclePropertyChangeMode:CONTINUOUS
@@ -187,6 +227,19 @@
         | VehicleArea:GLOBAL),
 
     /**
+     * Engine on
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     */
+    ENGINE_ON = (
+        0x0300
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BOOLEAN
+        | VehicleArea:GLOBAL),
+
+
+    /**
      * Temperature of engine coolant
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS
@@ -200,6 +253,19 @@
         | VehicleArea:GLOBAL),
 
     /**
+     * Engine oil level
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ
+     * @data_enum VehicleOilLevel
+     */
+    ENGINE_OIL_LEVEL = (
+        0x0303
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:INT32
+        | VehicleArea:GLOBAL),
+
+    /**
      * Temperature of engine oil
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE|VehiclePropertyChangeMode:CONTINUOUS
@@ -259,17 +325,97 @@
      *
      * @change_mode VehiclePropertyChangeMode:CONTINUOUS
      * @access VehiclePropertyAccess:READ
-     *
-     * @since o.mr1
      */
     WHEEL_TICK = (
       0x0306
       | VehiclePropertyGroup:SYSTEM
-      | VehiclePropertyType:COMPLEX
+      | VehiclePropertyType:MIXED
       | VehicleArea:GLOBAL),
 
 
     /**
+     * Fuel remaining in the the vehicle, in milliliters
+     *
+     * Value may not exceed INFO_FUEL_CAPACITY
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     * @unit VehicleUnit:MILLILITER
+     */
+    FUEL_LEVEL = (
+        0x0307
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:FLOAT
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Fuel door open
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     */
+    FUEL_DOOR_OPEN = (
+        0x0308
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BOOLEAN
+        | VehicleArea:GLOBAL),
+
+    /**
+     * EV battery level in WH, if EV or hybrid
+     *
+     * Value may not exceed INFO_EV_BATTERY_CAPACITY
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     * @unit VehicleUnit:WH
+     */
+    EV_BATTERY_LEVEL = (
+        0x0309
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:FLOAT
+        | VehicleArea:GLOBAL),
+
+    /**
+     * EV charge port open
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     */
+    EV_CHARGE_PORT_OPEN = (
+        0x030A
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BOOLEAN
+        | VehicleArea:GLOBAL),
+
+    /**
+     * EV charge port connected
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     */
+    EV_CHARGE_PORT_CONNECTED = (
+        0x030B
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BOOLEAN
+        | VehicleArea:GLOBAL),
+
+    /**
+     * EV instantaneous charge rate in milliwatts
+     *
+     * Positive value indicates battery is being charged.
+     * Negative value indicates battery being discharged.
+     *
+     * @change_mode VehiclePropertyChangeMode:STATIC
+     * @access VehiclePropertyAccess:READ
+     * @unit VehicleUnit:MW
+     */
+    EV_BATTERY_INSTANTANEOUS_CHARGE_RATE = (
+        0x030C
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:FLOAT
+        | VehicleArea:GLOBAL),
+
+    /**
      * Currently selected gear
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
@@ -300,7 +446,7 @@
      * Parking brake state.
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ
+     * @access VehiclePropertyAccess:READ_WRITE
      */
     PARKING_BRAKE_ON = (
         0x0402
@@ -309,6 +455,18 @@
         | VehicleArea:GLOBAL),
 
     /**
+     * Auto-apply parking brake.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    PARKING_BRAKE_AUTO_APPLY = (
+        0x0403
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BOOLEAN
+        | VehicleArea:GLOBAL),
+
+    /**
      * Driving status policy.
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
@@ -376,8 +534,6 @@
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ
-     *
-     * @since o.mr1
      */
     ABS_ACTIVE = (
         0x040A
@@ -390,8 +546,6 @@
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ
-     *
-     * @since o.mr1
      */
     TRACTION_CONTROL_ACTIVE = (
         0x040B
@@ -696,12 +850,14 @@
     /**
      * Fan Positions Available
      *
-     * This is a bit mask of fan positions available for the zone.  Each entry in
-     * vehicle_hvac_fan_direction is selected by bit position.  For instance, if
-     * only the FAN_DIRECTION_FACE (0x1) and FAN_DIRECTION_DEFROST (0x4) are available,
-     * then this value shall be set to 0x12.
-     *
-     * 0x12 = (1 << 1) | (1 << 4)
+     * This is a bit mask of fan positions available for the zone.  Each available fan direction is
+     * denoted by a separate entry in the vector.  A fan direction may have multiple bits from
+     * vehicle_hvac_fan_direction set.  For instance, a typical car may have the following setting:
+     *   - [0] = FAN_DIRECTION_FACE (0x1)
+     *   - [1] = FAN_DIRECTION_FLOOR (0x2)
+     *   - [2] = FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR (0x3)
+     *   - [3] = FAN_DIRECTION_DEFROST (0x4)
+     *   - [4] = FAN_DIRECTION_FLOOR | FAN_DIRECTION_DEFROST (0x6)
      *
      * @change_mode VehiclePropertyChangeMode:STATIC
      * @access VehiclePropertyAccess:READ
@@ -709,7 +865,7 @@
     HVAC_FAN_DIRECTION_AVAILABLE = (
         0x0511
         | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32
+        | VehiclePropertyType:INT32_VEC
         | VehicleArea:ZONE),
 
     /**
@@ -720,8 +876,6 @@
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ_WRITE
-     *
-     * @since o.mr1
      */
     HVAC_AUTO_RECIRC_ON = (
         0x0512
@@ -780,346 +934,6 @@
         | VehicleArea:GLOBAL),
 
     /**
-     * Represents audio focus state of Android side. Note that car's audio
-     * module must own audio focus and grant audio focus to Android side when
-     * requested by Android side. The focus has both per stream characteristics
-     * and global characteristics.
-     *
-     * Focus request (get of this property) must take the following form with indices defined
-     * by VehicleAudioFocusIndex:
-     *   int32Values[0]: VehicleAudioFocusRequest type
-     *   int32Values[1]: bit flags of streams requested by this focus request.
-     *                   There can be up to 32 streams.
-     *   int32Values[2]: External focus state flags. For request, only flag like
-     *                   VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG or
-     *                   VehicleAudioExtFocusFlag#MUTE_MEDIA_FLAG can be
-     *                   used.
-     *                   VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG is for case
-     *                   like radio where android side app still needs to hold
-     *                   focus but playback is done outside Android.
-     *                   VehicleAudioExtFocusFlag#MUTE_MEDIA_FLAG is for
-     *                   muting media channel including radio.
-     *                   VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG can be set
-     *                   even if android side releases focus (request type
-     *                   REQUEST_RELEASE). In that case, audio module must
-     *                   maintain mute state until user's explicit action to
-     *                   play some media.
-     *   int32Values[3]: Audio contexts wishing to be active. Use combination of
-     *                   flags from VehicleAudioContextFlag.
-     *                   This can be used as a hint to adjust audio policy or
-     *                   other policy decision.
-     *                   Note that there can be multiple context active at the
-     *                   same time. And android can send the same focus request
-     *                   type gain due to change in audio contexts.
-     * Note that each focus request can request multiple streams that is
-     * expected to be used for the current request. But focus request itself
-     * is global behavior as GAIN or GAIN_TRANSIENT expects all sounds played
-     * by car's audio module to stop. Note that stream already allocated to
-     * android before this focus request must not be affected by focus
-     * request.
-     *
-     * Focus response (set and subscription callback for this property) must
-     * take the following form with indices defined by VehicleAudioFocusIndex:
-     *   int32Values[0]: VehicleAudioFocusState type
-     *   int32Values[1]: bit flags of streams allowed.
-     *   int32Values[2]: External focus state: bit flags of currently active
-     *                   audio focus in car side (outside Android). Active
-     *                   audio focus does not necessarily mean currently
-     *                   playing, but represents the state of having focus or
-     *                   waiting for focus (pause state).
-     *                   One or combination of flags from
-     *                   VehicleAudioExtFocusFlag.
-     *                   0 means no active audio focus holder outside Android.
-     *                   The state must have following values for each
-     *                   VehicleAudioFocusState:
-     *                   GAIN: VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG
-     *                       when radio is active in Android side. Otherwise,
-     *                       VehicleAudioExtFocusFlag#NONE_FLAG.
-     *                   GAIN_TRANSIENT: Can be
-     *                       VehicleAudioExtFocusFlag#PERMANENT_FLAG or
-     *                       VehicleAudioExtFocusFlag#TRANSIENT_FLAG if android
-     *                       side has requested
-     *                       REQUEST_GAIN_TRANSIENT_MAY_DUCK and car side is
-     *                       ducking. Otherwise
-     *                       VehicleAudioExtFocusFlag#NONE_FLAG.
-     *                   LOSS: VehicleAudioExtFocusFlag#NONE_FLAG when no focus
-     *                       is active in car side.
-     *                       VehicleAudioExtFocusFlag#PERMANENT_FLAG when car
-     *                       side is playing something permanent.
-     *                   LOSS_TRANSIENT: must always be
-     *                       VehicleAudioExtFocusFlag#PERMANENT_FLAG
-     *   int32Values[3]: Audio context(s) allowed to be active. When responding positively to a
-     *                   focus request from Android, the request's original context must be
-     *                   repeated here. When taking focus away, or denying a request, the
-     *                   rejected or stopped context would have its corresponding bit cleared.
-     *
-     * A focus response must be sent per each focus request even if there is
-     * no change in focus state. This can happen in case like focus request
-     * only involving context change where android side still needs matching
-     * focus response to confirm that audio module has made necessary changes.
-     *
-     * If car does not support AUDIO_FOCUS, focus is assumed to be granted
-     * always.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     */
-    AUDIO_FOCUS = (
-        0x0900
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * A property to allow external component to control audio focus. Depending on
-     * H/W architecture, audio HAL may need to control audio focus while vehicle
-     * HAL is still interacting with upper layer. In such case, audio HAL may set
-     * this property and vehicle HAL may use this property value to decide
-     * response sent through AUDIO_FOCUS property.
-     * Data format is the same as AUDIO_FOCUS property.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     */
-    AUDIO_FOCUS_EXT_SYNC = (
-        0x0910
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to control audio volume of each audio context.
-     *
-     * VehiclePropConfig
-     *   configArray[0] : bit flags of all supported audio contexts from
-     *                    VehicleAudioContextFlag. If this is 0, audio volume
-     *                    is controlled per physical stream.
-     *   configArray[1] : flags defined in VehicleAudioVolumeCapabilityFlag to
-     *                    represent audio module's capability.
-     *   configArray[2..3] : reserved
-     *   configArray[4..N+3] : maximum values for each audio context, where N is
-     *                         the number of audio contexts provided in
-     *                         configArray[0], minimum value is always 0 which
-     *                         indicates mute state.
-     *
-     * Data type looks like:
-     *   int32Values[0] : audio context as defined in VehicleAudioContextFlag.
-     *                    If only physical stream is supported
-     *                    (configArray[0] == 0), this must represent physical
-     *                    stream number.
-     *   int32Values[1] : volume level, valid range is 0 (mute) to max level
-     *                    defined in the config.
-     *   int32Values[2] : One of VehicleAudioVolumeState.
-     *
-     * HAL implementations must check the incoming value of audio context
-     * field in get call to return the right volume.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     * @config_flags all audio contexts supported.
-     */
-    AUDIO_VOLUME = (
-        0x0901
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to allow audio volume sync from external components like audio HAL.
-     * Some vehicle HAL implementation may get volume control from audio HAL and in such
-     * case, setting AUDIO_VOLUME_EXT_SYNC property may trigger event in AUDIO_VOLUME property.
-     * Data format for this property is the same as AUDIO_VOLUME property.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     * @config_flags all audio contexts supported.
-     */
-    AUDIO_VOLUME_EXT_SYNC = (
-        0x0911
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property for handling volume limit set by user. This limits maximum
-     * volume that can be set per each context or physical stream.
-     *
-     * VehiclePropConfig
-     *   configArray[0] : bit flags of all supported audio contexts. If this is
-     *                    0, audio volume is controlled per physical stream.
-     *   configArray[1] : flags defined in VehicleAudioVolumeCapabilityFlag
-     *                    to represent audio module's capability.
-     *
-     * Data type looks like:
-     *   int32Values[0] : audio context as defined in VehicleAudioContextFlag.
-     *                    If only physical stream is supported
-     *                    (configArray[0] == 0), this must represent physical
-     *                    stream number.
-     *   int32Values[1] : maximum volume set to the stream. If there is no
-     *                    restriction, this value must be equal to
-     *                    AUDIO_VOLUME's max value.
-     *
-     * If car does not support this feature, this property must not be
-     * populated by HAL.
-     * HAL implementations must check the incoming value of audio context
-     * field in get call to return the right volume.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     * @config_flags all audio contexts supported.
-     */
-    AUDIO_VOLUME_LIMIT = (
-        0x0902
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to share audio routing policy of android side. This property is
-     * set at startup to pass audio policy in android side down to
-     * vehicle HAL and car audio module.
-     *
-     *   int32Values[0] : audio stream where the audio for the application
-     *                    context must be routed by default. Note that this is
-     *                    the default setting from system, but each app may
-     *                    still use different audio stream for whatever reason.
-     *   int32Values[1] : All audio contexts that must be sent through the
-     *                     physical stream. Flag is defined in
-     *                     VehicleAudioContextFlag.
-
-     * Setting of this property must be done for all available physical streams
-     * based on audio H/W variant information acquired from AUDIO_HW_VARIANT
-     * property.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:WRITE
-     */
-    AUDIO_ROUTING_POLICY = (
-        0x0903
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to return audio H/W variant type used in this car. This is a
-     * zero based index into the set of audio routing policies defined in
-     * R.array.audioRoutingPolicy on CarService, which  may be overlaid to
-     * support multiple variants. If this property does not exist, the default
-     * audio policy must be used.
-     *
-     * @change_mode VehiclePropertyChangeMode:STATIC
-     * @access VehiclePropertyAccess:READ
-     * @config_flags Additional info on audio H/W. Must use
-     *               VehicleAudioHwVariantConfigFlag for this.
-     */
-    AUDIO_HW_VARIANT = (
-        0x0904
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to pass hint on external audio routing. When android side
-     * request focus with VehicleAudioExtFocusflag, this
-     * property must be set before setting AUDIO_FOCUS property as a hint for
-     * external audio source routing.
-     * Note that setting this property alone must not trigger any change.
-     * Audio routing must be changed only when AUDIO_FOCUS property is set.
-     * Note that this property allows passing custom value as long as it is
-     * defined in VehiclePropConfig#configString. This allows supporting
-     * non-standard routing options through this property.
-     * It is recommended to use separate name space for custom property to
-     * prevent conflict in future android releases.
-     * Enabling each external routing option is done by enabling each bit flag
-     * for the routing.
-     * This property can support up to 128 external routings.
-     * To give full flexibility, there is no standard definition for each bit
-     * flag and assigning each bit flag to specific routing type is decided by
-     * VehiclePropConfig#configString.  VehiclePropConfig#configString has
-     * format of each entry separated by ',' and each entry has format of
-     * bitFlagPositon:typeString[:physicalStreamNumber].
-     *  bitFlagPosition: represents which bit flag will be set to enable this
-     *    routing. 0 means LSB in int32Values[0]. 31 will be MSB in
-     *    int32Values[0]. 127 will MSB in int32Values[3].
-     *  typeString: string representation of external routing. Some types are
-     *    already defined in AUDIO_EXT_ROUTING_SOURCE_* and use them first
-     *    before adding something custom. Applications will find each routing
-     *    using this string.
-     *  physicalStreamNumber: This part is optional and represents physical
-     *    stream to android which will be disabled when this routing is enabled.
-     *    If not specified, this routing must not affect physical streams to
-     *    android.
-     * As an example, let's assume a system with two physical streams, 0 for
-     * media and 1 for nav guidance. And let's assume external routing option
-     * of am fm radio, external navigation guidance, satellite radio, and one
-     * custom. Let's assume that radio and satellite replaces physical stream 0
-     * and external navigation replaces physical stream 1. And bit flag will be
-     * assigned in the order listed above. This configuration will look like
-     * this in config_string:
-     *  "0:RADIO_AM_FM:0,1:EXT_NAV_GUIDANCE:1,2:RADIO_SATELLITE:0,3:com.test.SOMETHING_CUSTOM"
-     * When android requests RADIO_AM_FM, int32Values[0] will be set to 0x1.
-     * When android requests RADIO_SATELLITE + EXT_NAV_GUIDANCE, int32Values[0]
-     * will be set to 0x2|0x4.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     * @config_string List of all avaiable external source in the system.
-     */
-    AUDIO_EXT_ROUTING_HINT = (
-        0x0905
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Represents state of audio stream. Audio HAL should set this when a stream is starting or
-     * ending. Car service can request focus for audio played without focus. If such feature
-     * is not required, this property does not need to be implemented.
-     * Car service only monitors setting of this property. It is up to each vehicle HAL
-     * implementation to add necessary action but default implementation will be doing nothing on
-     * this propery's set from audio HAL.
-     * Actual streaming of data should be done only after getting focus for the given stream from
-     * car audio module. Focus can be already granted when stream is started. Focus state can be
-     * monitored by monitoring AUDIO_FOCUS property. If car does not support
-     * AUDIO_FOCUS property, there is no need to monitor focus as focus is assumed to be
-     * granted always.
-     * Data has the following format:
-     *   int32_array[0] : vehicle_audio_stream_state, 0: stopped, 1: started
-     *   int32_array[1] : stream number like 0, 1, 2, ...
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     */
-    AUDIO_STREAM_STATE  = (
-        0x0906
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to control car specific audio parameters. Each parameter is defined as string key-
-     * value pair.
-     * set and event notification can pass multiple parameters using the
-     * following format:
-     *   key1=value1;key2=value2;...
-     * get call can request multiple parameters using the following format:
-     *   key1;key2;...
-     * Response for get call has the same format as set.
-     *
-     * VehiclePropConfig
-     *   configString: give list of all supported keys with ; as separator. For example:
-     *     key1;key2;...
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     */
-    AUDIO_PARAMETERS = (
-        0x907
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:STRING
-        | VehicleArea:GLOBAL),
-
-    /**
      * Property to control power state of application processor
      *
      * It is assumed that AP's power state is controller by separate power
@@ -1201,41 +1015,6 @@
         | VehicleArea:GLOBAL),
 
     /**
-     * Property to define instrument cluster information.
-     * For VehicleInstrumentClusterType:EXTERNAL_DISPLAY:
-     *  READ:
-     *   int32Values[0] : The current screen mode index. Screen mode is defined
-     *                    as a configuration in car service and represents
-     *                    which area of screen is renderable.
-     *   int32Values[1] : Android can render to instrument cluster (=1) or
-     *                    not(=0). When this is 0, instrument cluster may be
-     *                    rendering some information in the area allocated for
-     *                    android and android side rendering is invisible.
-     *  WRITE from android:
-     *   int32Values[0] : Preferred mode for android side. Depending on the app
-     *                    rendering to instrument cluster, preferred mode can
-     *                    change. Instrument cluster still needs to send
-     *                    event with new mode to trigger actual mode change.
-     *   int32Values[1] : The current app context relevant for instrument
-     *                    cluster. Use the same flag with
-     *                    VehicleAudioContextFlag but this context represents
-     *                    active apps, not active audio. Instrument cluster
-     *                    side may change mode depending on the currently
-     *                    active contexts.
-     *  When system boots up, Android side will write {0, 0, 0, 0} when it is
-     *  ready to render to instrument cluster. Before this message, rendering
-     *  from android must not be visible in the cluster.
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     * @configArray 0:VehicleInstrumentClusterType 1:hw type
-     */
-    INSTRUMENT_CLUSTER_INFO = (
-        0x0A20
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
      * Current date and time, encoded as Unix time.
      * This value denotes the number of seconds that have elapsed since
      * 1/1/1970.
@@ -1816,7 +1595,7 @@
         0x0BC0
         | VehiclePropertyGroup:SYSTEM
         | VehiclePropertyType:INT32
-        | VehicleArea:GLOBAL),
+        | VehicleArea:WINDOW),
 
     /**
      * Window Move
@@ -1833,7 +1612,7 @@
         0x0BC1
         | VehiclePropertyGroup:SYSTEM
         | VehiclePropertyType:INT32
-        | VehicleArea:GLOBAL),
+        | VehicleArea:WINDOW),
 
     /**
      * Window Vent Position
@@ -1850,7 +1629,7 @@
         0x0BC2
         | VehiclePropertyGroup:SYSTEM
         | VehiclePropertyType:INT32
-        | VehicleArea:GLOBAL),
+        | VehicleArea:WINDOW),
 
     /**
      * Window Vent Move
@@ -1867,7 +1646,7 @@
         0x0BC3
         | VehiclePropertyGroup:SYSTEM
         | VehiclePropertyType:INT32
-        | VehicleArea:GLOBAL),
+        | VehicleArea:WINDOW),
 
     /**
      * Window Lock
@@ -1881,13 +1660,13 @@
         0x0BC4
         | VehiclePropertyGroup:SYSTEM
         | VehiclePropertyType:BOOLEAN
-        | VehicleArea:GLOBAL),
+        | VehicleArea:WINDOW),
 
 
     /**
      * Vehicle Maps Service (VMS) message
      *
-     * This property uses COMPLEX data to communicate vms messages.
+     * This property uses MIXED data to communicate vms messages.
      *
      * Its contents are to be interpreted as follows:
      * the indices defined in VmsMessageIntegerValuesIndex are to be used to
@@ -1899,13 +1678,11 @@
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ_WRITE
-     *
-     * @since o.mr1
      */
     VEHICLE_MAP_SERVICE = (
         0x0C00
         | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:COMPLEX
+        | VehiclePropertyType:MIXED
         | VehicleArea:GLOBAL),
 
     /**
@@ -1948,13 +1725,11 @@
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ
-     *
-     * @since o.mr1
      */
     OBD2_LIVE_FRAME = (
       0x0D00
       | VehiclePropertyGroup:SYSTEM
-      | VehiclePropertyType:COMPLEX
+      | VehiclePropertyType:MIXED
       | VehicleArea:GLOBAL),
 
     /**
@@ -1980,13 +1755,11 @@
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ
-     *
-     * @since o.mr1
      */
     OBD2_FREEZE_FRAME = (
       0x0D01
       | VehiclePropertyGroup:SYSTEM
-      | VehiclePropertyType:COMPLEX
+      | VehiclePropertyType:MIXED
       | VehicleArea:GLOBAL),
 
     /**
@@ -2003,13 +1776,11 @@
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ
-     *
-     * @since o.mr1
      */
     OBD2_FREEZE_FRAME_INFO = (
       0x0D02
       | VehiclePropertyGroup:SYSTEM
-      | VehiclePropertyType:COMPLEX
+      | VehiclePropertyType:MIXED
       | VehicleArea:GLOBAL),
 
     /**
@@ -2031,25 +1802,99 @@
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:WRITE
-     *
-     * @since o.mr1
      */
     OBD2_FREEZE_FRAME_CLEAR = (
       0x0D03
       | VehiclePropertyGroup:SYSTEM
-      | VehiclePropertyType:COMPLEX
+      | VehiclePropertyType:MIXED
       | VehicleArea:GLOBAL),
 };
 
 /**
+ * Used by INFO_EV_CONNECTOR_TYPE to enumerate the type of connectors
+ * available to charge the vehicle.  Consistent with projection protocol.
+ */
+enum EvConnectorType : int32_t {
+    /**
+     * Default type if the vehicle does not know or report the EV connector
+     * type.
+     */
+    EV_CONNECTOR_TYPE_UNKNOWN = 0,
+    EV_CONNECTOR_TYPE_J1772 = 1,
+    EV_CONNECTOR_TYPE_MENNEKES = 2,
+    EV_CONNECTOR_TYPE_CHADEMO = 3,
+    EV_CONNECTOR_TYPE_COMBO_1 = 4,
+    EV_CONNECTOR_TYPE_COMBO_2 = 5,
+    EV_CONNECTOR_TYPE_TESLA_ROADSTER = 6,
+    EV_CONNECTOR_TYPE_TESLA_HPWC = 7,
+    EV_CONNECTOR_TYPE_TESLA_SUPERCHARGER = 8,
+    EV_CONNECTOR_TYPE_GBT = 9,
+
+    /**
+     * Connector type to use when no other types apply. Before using this
+     * value, work with Google to see if the EvConnectorType enum can be
+     * extended with an appropriate value.
+     */
+    EV_CONNECTOR_TYPE_OTHER = 101,
+};
+
+/**
+ * Used by INFO_FUEL_TYPE to enumerate the type of fuels this vehicle uses.
+ * Consistent with projection protocol.
+ */
+enum FuelType : int32_t {
+    /**
+     * Fuel type to use if the HU does not know on which types of fuel the vehicle
+     * runs. The use of this value is generally discouraged outside of aftermarket units.
+     */
+    FUEL_TYPE_UNKNOWN = 0,
+    /** Unleaded gasoline */
+    FUEL_TYPE_UNLEADED = 1,
+    /** Leaded gasoline */
+    FUEL_TYPE_LEADED = 2,
+    /** Diesel #1 */
+    FUEL_TYPE_DIESEL_1 = 3,
+    /** Diesel #2 */
+    FUEL_TYPE_DIESEL_2 = 4,
+    /** Biodiesel */
+    FUEL_TYPE_BIODIESEL = 5,
+    /** 85% ethanol/gasoline blend */
+    FUEL_TYPE_E85 = 6,
+    /** Liquified petroleum gas */
+    FUEL_TYPE_LPG = 7,
+    /** Compressed natural gas */
+    FUEL_TYPE_CNG = 8,
+    /** Liquified natural gas */
+    FUEL_TYPE_LNG = 9,
+    /** Electric */
+    FUEL_TYPE_ELECTRIC = 10,
+    /** Hydrogen fuel cell */
+    FUEL_TYPE_HYDROGEN = 11,
+    /**
+     * Fuel type to use when no other types apply. Before using this value, work with
+     * Google to see if the FuelType enum can be extended with an appropriate value.
+     */
+    FUEL_TYPE_OTHER = 12,
+};
+
+/**
  * Bit flags for fan direction
  */
 enum VehicleHvacFanDirection : int32_t {
     FACE = 0x1,
     FLOOR = 0x2,
-    FACE_AND_FLOOR = 0x3,
     DEFROST = 0x4,
-    DEFROST_AND_FLOOR = 0x5,
+};
+
+enum VehicleOilLevel : int32_t {
+    /**
+     * Oil level values
+     */
+    CRITICALLY_LOW = 0,
+    LOW = 1,
+    NORMAL = 2,
+    HIGH = 3,
+    ERROR = 4,
 };
 
 /**
@@ -2060,256 +1905,6 @@
     VEHICLE_RADIO_PRESET_MIN_VALUE = 1,
 };
 
-enum VehicleAudioFocusRequest : int32_t {
-    REQUEST_GAIN = 0x1,
-    REQUEST_GAIN_TRANSIENT = 0x2,
-    REQUEST_GAIN_TRANSIENT_MAY_DUCK = 0x3,
-    /**
-     * This is for the case where android side plays sound like UI feedback
-     * and car side does not need to duck existing playback as long as
-     * requested stream is available.
-     */
-    REQUEST_GAIN_TRANSIENT_NO_DUCK = 0x4,
-    REQUEST_RELEASE = 0x5,
-};
-
-enum VehicleAudioFocusState : int32_t {
-    /**
-     * Android side has permanent focus and can play allowed streams.
-     */
-    STATE_GAIN = 0x1,
-
-    /**
-     * Android side has transient focus and can play allowed streams.
-     */
-    STATE_GAIN_TRANSIENT = 0x2,
-
-    /**
-     * Car audio module is playing guidance kind of sound outside Android.
-     * Android side can still play through allowed streams with ducking.
-     */
-    STATE_LOSS_TRANSIENT_CAN_DUCK = 0x3,
-
-    /**
-     * Car audio module is playing transient sound outside Android. Android side
-     * must stop playing any sounds.
-     */
-    STATE_LOSS_TRANSIENT = 0x4,
-
-    /**
-     * Android side has lost focus and cannot play any sound.
-     */
-    STATE_LOSS = 0x5,
-
-    /**
-     * car audio module is playing safety critical sound, and Android side cannot
-     * request focus until the current state is finished. car audio module
-     * restore it to the previous state when it can allow Android to play.
-     */
-    STATE_LOSS_TRANSIENT_EXLCUSIVE = 0x6,
-};
-
-/**
- * Flags to represent multiple streams by combining these.
- */
-enum VehicleAudioStreamFlag : int32_t {
-    STREAM0_FLAG = (0x1 << 0),
-    STREAM1_FLAG = (0x1 << 1),
-    STREAM2_FLAG = (0x1 << 2),
-};
-
-/**
- * Represents stream number (always 0 to N -1 where N is max number of streams).
- * Can be used for audio related property expecting one stream.
- */
-enum VehicleAudioStream : int32_t {
-    STREAM0 = 0,
-    STREAM1 = 1,
-};
-
-/**
- * Flag to represent external focus state (outside Android).
- */
-enum VehicleAudioExtFocusFlag : int32_t {
-    /**
-     * No external focus holder.
-     */
-    NONE_FLAG = 0x0,
-
-    /**
-     * Car side (outside Android) has component holding GAIN kind of focus state.
-     */
-    PERMANENT_FLAG = 0x1,
-
-    /**
-     * Car side (outside Android) has component holding GAIN_TRANSIENT kind of
-     * focus state.
-     */
-    TRANSIENT_FLAG = 0x2,
-
-    /**
-     * Car side is expected to play something while focus is held by Android side.
-     * One example can be radio attached in car side. But Android's radio app
-     * still must have focus, and Android side must be in GAIN state, but
-     * media stream will not be allocated to Android side and car side can play
-     * radio any time while this flag is active.
-     */
-    PLAY_ONLY_FLAG = 0x4,
-
-    /**
-     * Car side must mute any media including radio. This can be used with any
-     * focus request including GAIN* and RELEASE.
-     */
-    MUTE_MEDIA_FLAG = 0x8,
-};
-
-/**
- * Index in int32Values for VehicleProperty#AUDIO_FOCUS property.
- */
-enum VehicleAudioFocusIndex : int32_t {
-    FOCUS = 0,
-    STREAMS = 1,
-    EXTERNAL_FOCUS_STATE = 2,
-    AUDIO_CONTEXTS = 3,
-};
-
-/**
- * Flags to tell the current audio context.
- */
-enum VehicleAudioContextFlag : int32_t {
-    /** Music playback is currently active. */
-    MUSIC_FLAG = 0x1,
-
-    /** Navigation is currently running. */
-    NAVIGATION_FLAG = 0x2,
-
-    /** Voice command session is currently running. */
-    VOICE_COMMAND_FLAG = 0x4,
-
-    /** Voice call is currently active. */
-    CALL_FLAG = 0x8,
-
-    /**
-     * Alarm is active.
-     * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY.
-     */
-    ALARM_FLAG = 0x10,
-
-    /**
-     * Notification sound is active.
-     * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY.
-     */
-    NOTIFICATION_FLAG = 0x20,
-
-    /**
-     * Context unknown. Only used for VehicleProperty#AUDIO_ROUTING_POLICY to
-     * represent default stream for unknown contents.
-     */
-    UNKNOWN_FLAG = 0x40,
-
-    /** Safety alert / warning is played. */
-    SAFETY_ALERT_FLAG = 0x80,
-
-    /** CD / DVD kind of audio is played */
-    CD_ROM_FLAG = 0x100,
-
-    /** Aux audio input is played */
-    AUX_AUDIO_FLAG = 0x200,
-
-    /** system sound like UI feedback */
-    SYSTEM_SOUND_FLAG = 0x400,
-
-    /** Radio is played */
-    RADIO_FLAG = 0x800,
-
-    /** Ext source is played. This is for tagging generic ext sources. */
-    EXT_SOURCE_FLAG = 0x1000,
-
-    /** The phone ring tone is played */
-    RINGTONE_FLAG = 0x2000
-};
-
-/**
- * flags to represent capability of audio volume property.
- * used in configArray[1] of VehiclePropConfig.
- */
-enum VehicleAudioVolumeCapabilityFlag : int32_t {
-    /**
-     * External audio module or vehicle hal has persistent storage to keep the
-     * volume level. When this is set, the audio volume level for each context
-     * will be retrieved from the property when the system starts up.
-     * And external audio module is also expected to adjust volume automatically
-     * whenever there is an audio context change.
-     * When this flag is not set, android side will assume that there is no
-     * persistent storage and the value stored in the android side will be used to
-     * initialize the volume level, and android side will set volume level
-     * of each physical stream whenever there is an audio context change.
-     */
-    PERSISTENT_STORAGE = 0x1,
-
-    /**
-     * [DEPRECATED]
-     * When this flag is set, the H/W can support only single master volume for
-     * all streams. There is no way to set volume level differently for each stream
-     * or context.
-     */
-    MASTER_VOLUME_ONLY = 0x2,
-};
-
-/**
- * enum to represent audio volume state.
- */
-enum VehicleAudioVolumeState : int32_t {
-    STATE_OK = 0,
-
-    /**
-     * Audio volume has reached volume limit set in
-     * VehicleProperty#AUDIO_VOLUME_LIMIT and user's request to increase volume
-     * further is not allowed.
-     */
-    STATE_LIMIT_REACHED = 1,
-};
-
-/**
- * Index in int32Values for VehicleProperty#AUDIO_VOLUME property.
- */
-enum VehicleAudioVolumeIndex : int32_t {
-    STREAM = 0,
-    VOLUME = 1,
-    STATE = 2,
-};
-
-/**
- * Index in int32Values for VehicleProperty#AUDIO_VOLUME_LIMIT property.
- */
-enum VehicleAudioVolumeLimitIndex : int32_t {
-    STREAM = 0,
-    MAX_VOLUME = 1,
-};
-
-/**
- * Index in int32Values for VehicleProperty#AUDIO_ROUTING_POLICY property.
- */
-enum VehicleAudioRoutingPolicyIndex : int32_t {
-    STREAM = 0,
-    CONTEXTS = 1,
-};
-
-/**
- * Flag to be used in VehiclePropConfig#configFlags for
- * VehicleProperty#AUDIO_HW_VARIANT.
- */
-enum VehicleAudioHwVariantConfigFlag : int32_t {
-  /**
-   * Flag to tell that radio is internal to android and radio must
-   * be treated like other android stream like media.
-   * When this flag is not set or AUDIO_HW_VARIANT does not exist,
-   * radio is treated as external module. This may affect audio focus
-   * handling as well.
-   */
-  INTERNAL_RADIO_FLAG = 0x1,
-};
-
 enum VehicleApPowerStateConfigFlag : int32_t /* NOTE: type is guessed */ {
     /**
      * AP can enter deep sleep state. If not set, AP will always shutdown from
@@ -2473,25 +2068,6 @@
 };
 
 /**
- * Represents instrument cluster type available in system
- */
-enum VehicleInstrumentClusterType : int32_t {
-  /** Android has no access to instument cluster */
-  NONE = 0,
-
-  /**
-   * Instrument cluster can communicate through vehicle hal with additional
-   * properties to exchange meta-data
-   */
-  HAL_INTERFACE = 1,
-
-  /**
-   * Instrument cluster is external display where android can render contents
-   */
-  EXTERNAL_DISPLAY = 2,
-};
-
-/**
  * Units used for int or float type with no attached enum types.
  */
 enum VehicleUnit : int32_t {
@@ -2511,6 +2087,12 @@
     NANO_SECS      = 0x50,
     SECS           = 0x53,
     YEAR           = 0x59,
+
+    // Electrical Units
+    WATT_HOUR      = 0x60,
+    MILLIAMPERE    = 0x61,
+    MILLIVOLT      = 0x62,
+    MILLIWATTS     = 0x63,
 };
 
   /**
@@ -2570,6 +2152,21 @@
 };
 
 /**
+ * Property status is a dynamic value that may change based on the vehicle state.
+ */
+enum VehiclePropertyStatus : int32_t {
+    /** Property is available and behaving normally */
+    AVAILABLE   = 0x00,
+    /**
+     * Property is not available, for read and/or write.  This is a transient state, as the
+     *  property is expected to be available at a later time.
+     */
+    UNAVAILABLE = 0x01,
+    /** There is an error with this property. */
+    ERROR       = 0x02,
+};
+
+/**
  * Car states.
  *
  * The driving states determine what features of the UI will be accessible.
@@ -2613,20 +2210,15 @@
   ROW_1_LEFT = 0x00000001,
   ROW_1_CENTER = 0x00000002,
   ROW_1_RIGHT = 0x00000004,
-  ROW_1 = 0x00000008,
   ROW_2_LEFT = 0x00000010,
   ROW_2_CENTER = 0x00000020,
   ROW_2_RIGHT = 0x00000040,
-  ROW_2 = 0x00000080,
   ROW_3_LEFT = 0x00000100,
   ROW_3_CENTER = 0x00000200,
   ROW_3_RIGHT = 0x00000400,
-  ROW_3 = 0x00000800,
   ROW_4_LEFT = 0x00001000,
   ROW_4_CENTER = 0x00002000,
   ROW_4_RIGHT = 0x00004000,
-  ROW_4 = 0x00008000,
-  WHOLE_CABIN = 0x80000000,
 };
 
 /**
@@ -2714,13 +2306,6 @@
     VehiclePropertyChangeMode changeMode;
 
     /**
-     * Some of the properties may have associated areas (for example, some hvac
-     * properties are associated with VehicleAreaZone), in these
-     * cases the config may contain an ORed value for the associated areas.
-     */
-    int32_t supportedAreas;
-
-    /**
      * Contains per-area configuration.
      */
     vec<VehicleAreaConfig> areaConfigs;
@@ -2773,6 +2358,9 @@
      */
     int32_t areaId;
 
+    /** Status of the property */
+    VehiclePropertyStatus status;
+
     /**
      * Contains value for a single property. Depending on property data type of
      * this property (VehiclePropetyType) one field of this structure must be filled in.
@@ -2885,12 +2473,6 @@
     int32_t propId;
 
     /**
-     * Area ids - this must be a bit mask of areas to subscribe or 0 to subscribe
-     * to all areas.
-     */
-    int32_t vehicleAreas;
-
-    /**
      * Sample rate in Hz.
      *
      * Must be provided for properties with
@@ -3295,9 +2877,42 @@
      * A message from the VMS service to the subscribers or from the publishers to the VMS service
      * with a serialized VMS data packet as defined in the VMS protocol.
      *
-     * This message type uses enum VmsBaseMessageIntegerValuesIndex.
+     * This message type uses enum VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.
      */
     DATA = 12,
+
+    /**
+     * A request from the publishers to the VMS service to get a Publisher ID for a serialized VMS
+     * provider description packet as defined in the VMS protocol.
+     *
+     * This message type uses enum VmsBaseMessageIntegerValuesIndex.
+     */
+    PUBLISHER_ID_REQUEST = 13,
+
+    /**
+     * A response from the VMS service to the publisher that contains a provider description packet
+     * and the publisher ID assigned to it.
+     *
+     * This message type uses enum VmsPublisherInformationIntegerValuesIndex.
+     */
+    PUBLISHER_ID_RESPONSE = 14,
+
+    /**
+     * A request from the subscribers to the VMS service to get information for a Publisher ID.
+     *
+     * This message type uses enum VmsPublisherInformationIntegerValuesIndex.
+     */
+    PUBLISHER_INFORMATION_REQUEST = 15,
+
+    /**
+     * A response from the VMS service to the subscribers that contains a provider description packet
+     * and the publisher ID assigned to it.
+     *
+     * This message type uses enum VmsPublisherInformationIntegerValuesIndex.
+     */
+    PUBLISHER_INFORMATION_RESPONSE = 16,
+
+    LAST_VMS_MESSAGE_TYPE = PUBLISHER_INFORMATION_RESPONSE,
 };
 
 /**
@@ -3325,7 +2940,8 @@
 
 /*
  * A VMS message with a layer and publisher ID is sent as part of a
- * VmsMessageType.SUBSCRIBE_TO_PUBLISHER and VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER messages.
+ * VmsMessageType.SUBSCRIBE_TO_PUBLISHER, VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER messages and
+ * VmsMessageType.DATA .
  */
 enum VmsMessageWithLayerAndPublisherIdIntegerValuesIndex : VmsMessageWithLayerIntegerValuesIndex {
     PUBLISHER_ID = 4,
@@ -3394,3 +3010,11 @@
     LAYERS_START = 3,
 };
 
+/*
+ * Publishers send the VMS service their information and assigned in response a publisher ID.
+ * Subscribers can request the publisher information for a publisher ID they received in other messages.
+ */
+enum VmsPublisherInformationIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex {
+    PUBLISHER_ID = 1,
+};
+
diff --git a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
index aa767a6..123d339 100644
--- a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
+++ b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
@@ -1,4 +1,4 @@
-service fps_hal /vendor/bin/hw/android.hardware.biometrics.fingerprint@2.1-service
+service vendor.fps_hal /vendor/bin/hw/android.hardware.biometrics.fingerprint@2.1-service
     # "class hal" causes a race condition on some devices due to files created
     # in /data. As a workaround, postpone startup until later in boot once
     # /data is mounted.
diff --git a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
index 47cc13e..e1f5faa 100644
--- a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
+++ b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
@@ -1,14 +1,14 @@
-service bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service
+service vendor.bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service
     class hal
     user bluetooth
     group bluetooth
     writepid /dev/stune/foreground/tasks
 
 on property:vts.native_server.on=1 && property:ro.build.type=userdebug
-    stop bluetooth-1-0
+    stop vendor.bluetooth-1-0
 on property:vts.native_server.on=1 && property:ro.build.type=eng
-    stop bluetooth-1-0
+    stop vendor.bluetooth-1-0
 on property:vts.native_server.on=0 && property:ro.build.type=userdebug
-    start bluetooth-1-0
+    start vendor.bluetooth-1-0
 on property:vts.native_server.on=0 && property:ro.build.type=eng
-    start bluetooth-1-0
+    start vendor.bluetooth-1-0
diff --git a/boot/1.0/default/android.hardware.boot@1.0-service.rc b/boot/1.0/default/android.hardware.boot@1.0-service.rc
index 68e7c22..32f3a45 100644
--- a/boot/1.0/default/android.hardware.boot@1.0-service.rc
+++ b/boot/1.0/default/android.hardware.boot@1.0-service.rc
@@ -1,4 +1,4 @@
-service boot-hal-1-0 /vendor/bin/hw/android.hardware.boot@1.0-service
+service vendor.boot-hal-1-0 /vendor/bin/hw/android.hardware.boot@1.0-service
     class early_hal
     user root
     group root
diff --git a/broadcastradio/1.1/default/Android.bp b/broadcastradio/1.1/default/Android.bp
deleted file mode 100644
index 6d26b11..0000000
--- a/broadcastradio/1.1/default/Android.bp
+++ /dev/null
@@ -1,47 +0,0 @@
-//
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_binary {
-    name: "android.hardware.broadcastradio@1.1-service",
-    init_rc: ["android.hardware.broadcastradio@1.1-service.rc"],
-    vendor: true,
-    relative_install_path: "hw",
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-    ],
-    srcs: [
-        "BroadcastRadio.cpp",
-        "BroadcastRadioFactory.cpp",
-        "Tuner.cpp",
-        "VirtualProgram.cpp",
-        "VirtualRadio.cpp",
-        "service.cpp"
-    ],
-    static_libs: [
-        "android.hardware.broadcastradio@1.1-utils-lib",
-    ],
-    shared_libs: [
-        "android.hardware.broadcastradio@1.0",
-        "android.hardware.broadcastradio@1.1",
-        "libbase",
-        "libhidlbase",
-        "libhidltransport",
-        "liblog",
-        "libutils",
-    ],
-}
diff --git a/broadcastradio/1.1/default/BroadcastRadio.cpp b/broadcastradio/1.1/default/BroadcastRadio.cpp
deleted file mode 100644
index 1bcfd82..0000000
--- a/broadcastradio/1.1/default/BroadcastRadio.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "BroadcastRadioDefault.module"
-#define LOG_NDEBUG 0
-
-#include "BroadcastRadio.h"
-
-#include <log/log.h>
-
-#include "resources.h"
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-using V1_0::Band;
-using V1_0::BandConfig;
-using V1_0::Class;
-using V1_0::Deemphasis;
-using V1_0::Rds;
-
-using std::lock_guard;
-using std::map;
-using std::mutex;
-using std::vector;
-
-// clang-format off
-static const map<Class, ModuleConfig> gModuleConfigs{
-    {Class::AM_FM, ModuleConfig({
-        "Digital radio mock",
-        {  // amFmBands
-            AmFmBandConfig({
-                Band::AM,
-                153,         // lowerLimit
-                26100,       // upperLimit
-                {5, 9, 10},  // spacings
-            }),
-            AmFmBandConfig({
-                Band::FM,
-                65800,           // lowerLimit
-                108000,          // upperLimit
-                {10, 100, 200},  // spacings
-            }),
-            AmFmBandConfig({
-                Band::AM_HD,
-                153,         // lowerLimit
-                26100,       // upperLimit
-                {5, 9, 10},  // spacings
-            }),
-            AmFmBandConfig({
-                Band::FM_HD,
-                87700,   // lowerLimit
-                107900,  // upperLimit
-                {200},   // spacings
-            }),
-        },
-    })},
-
-    {Class::SAT, ModuleConfig({
-        "Satellite radio mock",
-        {},  // amFmBands
-    })},
-};
-// clang-format on
-
-BroadcastRadio::BroadcastRadio(Class classId)
-    : mClassId(classId), mConfig(gModuleConfigs.at(classId)) {}
-
-bool BroadcastRadio::isSupported(Class classId) {
-    return gModuleConfigs.find(classId) != gModuleConfigs.end();
-}
-
-Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) {
-    ALOGV("%s", __func__);
-    return getProperties_1_1(
-        [&](const Properties& properties) { _hidl_cb(Result::OK, properties.base); });
-}
-
-Return<void> BroadcastRadio::getProperties_1_1(getProperties_1_1_cb _hidl_cb) {
-    ALOGV("%s", __func__);
-    Properties prop11 = {};
-    auto& prop10 = prop11.base;
-
-    prop10.classId = mClassId;
-    prop10.implementor = "Google";
-    prop10.product = mConfig.productName;
-    prop10.numTuners = 1;
-    prop10.numAudioSources = 1;
-    prop10.supportsCapture = false;
-    prop11.supportsBackgroundScanning = false;
-    prop11.supportedProgramTypes = hidl_vec<uint32_t>({
-        static_cast<uint32_t>(ProgramType::AM), static_cast<uint32_t>(ProgramType::FM),
-        static_cast<uint32_t>(ProgramType::AM_HD), static_cast<uint32_t>(ProgramType::FM_HD),
-    });
-    prop11.supportedIdentifierTypes = hidl_vec<uint32_t>({
-        static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY),
-        static_cast<uint32_t>(IdentifierType::RDS_PI),
-        static_cast<uint32_t>(IdentifierType::HD_STATION_ID_EXT),
-        static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL),
-    });
-    prop11.vendorInfo = hidl_vec<VendorKeyValue>({
-        {"com.google.dummy", "dummy"},
-    });
-
-    prop10.bands.resize(mConfig.amFmBands.size());
-    for (size_t i = 0; i < mConfig.amFmBands.size(); i++) {
-        auto& src = mConfig.amFmBands[i];
-        auto& dst = prop10.bands[i];
-
-        dst.type = src.type;
-        dst.antennaConnected = true;
-        dst.lowerLimit = src.lowerLimit;
-        dst.upperLimit = src.upperLimit;
-        dst.spacings = src.spacings;
-
-        if (utils::isAm(src.type)) {
-            dst.ext.am.stereo = true;
-        } else if (utils::isFm(src.type)) {
-            dst.ext.fm.deemphasis = static_cast<Deemphasis>(Deemphasis::D50 | Deemphasis::D75);
-            dst.ext.fm.stereo = true;
-            dst.ext.fm.rds = static_cast<Rds>(Rds::WORLD | Rds::US);
-            dst.ext.fm.ta = true;
-            dst.ext.fm.af = true;
-            dst.ext.fm.ea = true;
-        }
-    }
-
-    _hidl_cb(prop11);
-    return Void();
-}
-
-Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio __unused,
-                                       const sp<V1_0::ITunerCallback>& callback,
-                                       openTuner_cb _hidl_cb) {
-    ALOGV("%s(%s)", __func__, toString(config.type).c_str());
-    lock_guard<mutex> lk(mMut);
-
-    auto oldTuner = mTuner.promote();
-    if (oldTuner != nullptr) {
-        ALOGI("Force-closing previously opened tuner");
-        oldTuner->forceClose();
-        mTuner = nullptr;
-    }
-
-    sp<Tuner> newTuner = new Tuner(mClassId, callback);
-    mTuner = newTuner;
-    if (mClassId == Class::AM_FM) {
-        auto ret = newTuner->setConfiguration(config);
-        if (ret != Result::OK) {
-            _hidl_cb(Result::INVALID_ARGUMENTS, {});
-            return Void();
-        }
-    }
-
-    _hidl_cb(Result::OK, newTuner);
-    return Void();
-}
-
-Return<void> BroadcastRadio::getImage(int32_t id, getImage_cb _hidl_cb) {
-    ALOGV("%s(%x)", __func__, id);
-
-    if (id == resources::demoPngId) {
-        _hidl_cb(std::vector<uint8_t>(resources::demoPng, std::end(resources::demoPng)));
-        return {};
-    }
-
-    ALOGI("Image %x doesn't exists", id);
-    _hidl_cb({});
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
diff --git a/broadcastradio/1.1/default/BroadcastRadio.h b/broadcastradio/1.1/default/BroadcastRadio.h
deleted file mode 100644
index a96a2ab..0000000
--- a/broadcastradio/1.1/default/BroadcastRadio.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H
-#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H
-
-#include "Tuner.h"
-
-#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
-#include <android/hardware/broadcastradio/1.1/types.h>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-struct AmFmBandConfig {
-    V1_0::Band type;
-    uint32_t lowerLimit;  // kHz
-    uint32_t upperLimit;  // kHz
-    std::vector<uint32_t> spacings;  // kHz
-};
-
-struct ModuleConfig {
-    std::string productName;
-    std::vector<AmFmBandConfig> amFmBands;
-};
-
-struct BroadcastRadio : public V1_1::IBroadcastRadio {
-    /**
-     * Constructs new broadcast radio module.
-     *
-     * Before calling a constructor with a given classId, it must be checked with isSupported
-     * method first. Otherwise it results in undefined behaviour.
-     *
-     * @param classId type of a radio.
-     */
-    BroadcastRadio(V1_0::Class classId);
-
-    /**
-     * Checks, if a given radio type is supported.
-     *
-     * @param classId type of a radio.
-     */
-    static bool isSupported(V1_0::Class classId);
-
-    // V1_1::IBroadcastRadio methods
-    Return<void> getProperties(getProperties_cb _hidl_cb) override;
-    Return<void> getProperties_1_1(getProperties_1_1_cb _hidl_cb) override;
-    Return<void> openTuner(const V1_0::BandConfig& config, bool audio,
-                           const sp<V1_0::ITunerCallback>& callback,
-                           openTuner_cb _hidl_cb) override;
-    Return<void> getImage(int32_t id, getImage_cb _hidl_cb);
-
-   private:
-    std::mutex mMut;
-    V1_0::Class mClassId;
-    ModuleConfig mConfig;
-    wp<Tuner> mTuner;
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H
diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.cpp b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
deleted file mode 100644
index f57bc79..0000000
--- a/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "BroadcastRadioDefault.factory"
-#define LOG_NDEBUG 0
-
-#include "BroadcastRadioFactory.h"
-
-#include "BroadcastRadio.h"
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-using V1_0::Class;
-
-using std::vector;
-
-static const vector<Class> gAllClasses = {
-    Class::AM_FM, Class::SAT, Class::DT,
-};
-
-IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name __unused) {
-    return new BroadcastRadioFactory();
-}
-
-BroadcastRadioFactory::BroadcastRadioFactory() {
-    for (auto&& classId : gAllClasses) {
-        if (!BroadcastRadio::isSupported(classId)) continue;
-        mRadioModules[classId] = new BroadcastRadio(classId);
-    }
-}
-
-Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) {
-    ALOGV("%s(%s)", __func__, toString(classId).c_str());
-
-    auto moduleIt = mRadioModules.find(classId);
-    if (moduleIt == mRadioModules.end()) {
-        _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
-    } else {
-        _hidl_cb(Result::OK, moduleIt->second);
-    }
-
-    return Void();
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.h b/broadcastradio/1.1/default/BroadcastRadioFactory.h
deleted file mode 100644
index 8b67ac3..0000000
--- a/broadcastradio/1.1/default/BroadcastRadioFactory.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H
-#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H
-
-#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
-#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
-#include <android/hardware/broadcastradio/1.1/types.h>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-extern "C" IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name);
-
-struct BroadcastRadioFactory : public IBroadcastRadioFactory {
-    BroadcastRadioFactory();
-
-    // V1_0::IBroadcastRadioFactory methods
-    Return<void> connectModule(V1_0::Class classId, connectModule_cb _hidl_cb) override;
-
-   private:
-    std::map<V1_0::Class, sp<IBroadcastRadio>> mRadioModules;
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H
diff --git a/broadcastradio/1.1/default/OWNERS b/broadcastradio/1.1/default/OWNERS
deleted file mode 100644
index 0c27b71..0000000
--- a/broadcastradio/1.1/default/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Automotive team
-egranata@google.com
-keunyoung@google.com
-twasilczyk@google.com
diff --git a/broadcastradio/1.1/default/Tuner.cpp b/broadcastradio/1.1/default/Tuner.cpp
deleted file mode 100644
index 9a34cb1..0000000
--- a/broadcastradio/1.1/default/Tuner.cpp
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BroadcastRadioDefault.tuner"
-#define LOG_NDEBUG 0
-
-#include "BroadcastRadio.h"
-#include "Tuner.h"
-
-#include <broadcastradio-utils/Utils.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-using namespace std::chrono_literals;
-
-using V1_0::Band;
-using V1_0::BandConfig;
-using V1_0::Class;
-using V1_0::Direction;
-using utils::HalRevision;
-
-using std::chrono::milliseconds;
-using std::lock_guard;
-using std::move;
-using std::mutex;
-using std::sort;
-using std::vector;
-
-const struct {
-    milliseconds config = 50ms;
-    milliseconds scan = 200ms;
-    milliseconds step = 100ms;
-    milliseconds tune = 150ms;
-} gDefaultDelay;
-
-Tuner::Tuner(V1_0::Class classId, const sp<V1_0::ITunerCallback>& callback)
-    : mClassId(classId),
-      mCallback(callback),
-      mCallback1_1(ITunerCallback::castFrom(callback).withDefault(nullptr)),
-      mVirtualRadio(getRadio(classId)),
-      mIsAnalogForced(false) {}
-
-void Tuner::forceClose() {
-    lock_guard<mutex> lk(mMut);
-    mIsClosed = true;
-    mThread.cancelAll();
-}
-
-Return<Result> Tuner::setConfiguration(const BandConfig& config) {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(mMut);
-    if (mIsClosed) return Result::NOT_INITIALIZED;
-    if (mClassId != Class::AM_FM) {
-        ALOGE("Can't set AM/FM configuration on SAT/DT radio tuner");
-        return Result::INVALID_STATE;
-    }
-
-    if (config.lowerLimit >= config.upperLimit) return Result::INVALID_ARGUMENTS;
-
-    auto task = [this, config]() {
-        ALOGI("Setting AM/FM config");
-        lock_guard<mutex> lk(mMut);
-
-        mAmfmConfig = move(config);
-        mAmfmConfig.antennaConnected = true;
-        mCurrentProgram = utils::make_selector(mAmfmConfig.type, mAmfmConfig.lowerLimit);
-
-        if (utils::isFm(mAmfmConfig.type)) {
-            mVirtualRadio = std::ref(getFmRadio());
-        } else {
-            mVirtualRadio = std::ref(getAmRadio());
-        }
-
-        mIsAmfmConfigSet = true;
-        mCallback->configChange(Result::OK, mAmfmConfig);
-    };
-    mThread.schedule(task, gDefaultDelay.config);
-
-    return Result::OK;
-}
-
-Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(mMut);
-
-    if (!mIsClosed && mIsAmfmConfigSet) {
-        _hidl_cb(Result::OK, mAmfmConfig);
-    } else {
-        _hidl_cb(Result::NOT_INITIALIZED, {});
-    }
-    return {};
-}
-
-// makes ProgramInfo that points to no program
-static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) {
-    ProgramInfo info11 = {};
-    auto& info10 = info11.base;
-
-    utils::getLegacyChannel(selector, &info10.channel, &info10.subChannel);
-    info11.selector = selector;
-    info11.flags |= ProgramInfoFlags::MUTED;
-
-    return info11;
-}
-
-HalRevision Tuner::getHalRev() const {
-    if (mCallback1_1 != nullptr) {
-        return HalRevision::V1_1;
-    } else {
-        return HalRevision::V1_0;
-    }
-}
-
-void Tuner::tuneInternalLocked(const ProgramSelector& sel) {
-    VirtualProgram virtualProgram;
-    if (mVirtualRadio.get().getProgram(sel, virtualProgram)) {
-        mCurrentProgram = virtualProgram.selector;
-        mCurrentProgramInfo = virtualProgram.getProgramInfo(getHalRev());
-    } else {
-        mCurrentProgram = sel;
-        mCurrentProgramInfo = makeDummyProgramInfo(sel);
-    }
-    mIsTuneCompleted = true;
-
-    if (mCallback1_1 == nullptr) {
-        mCallback->tuneComplete(Result::OK, mCurrentProgramInfo.base);
-    } else {
-        mCallback1_1->tuneComplete_1_1(Result::OK, mCurrentProgramInfo.selector);
-        mCallback1_1->currentProgramInfoChanged(mCurrentProgramInfo);
-    }
-}
-
-Return<Result> Tuner::scan(Direction direction, bool skipSubChannel __unused) {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(mMut);
-    if (mIsClosed) return Result::NOT_INITIALIZED;
-
-    auto list = mVirtualRadio.get().getProgramList();
-
-    if (list.empty()) {
-        mIsTuneCompleted = false;
-        auto task = [this, direction]() {
-            ALOGI("Performing failed scan %s", toString(direction).c_str());
-
-            if (mCallback1_1 == nullptr) {
-                mCallback->tuneComplete(Result::TIMEOUT, {});
-            } else {
-                mCallback1_1->tuneComplete_1_1(Result::TIMEOUT, {});
-            }
-        };
-        mThread.schedule(task, gDefaultDelay.scan);
-
-        return Result::OK;
-    }
-
-    // Not optimal (O(sort) instead of O(n)), but not a big deal here;
-    // also, it's likely that list is already sorted (so O(n) anyway).
-    sort(list.begin(), list.end());
-    auto current = mCurrentProgram;
-    auto found = lower_bound(list.begin(), list.end(), VirtualProgram({current}));
-    if (direction == Direction::UP) {
-        if (found < list.end() - 1) {
-            if (utils::tunesTo(current, found->selector)) found++;
-        } else {
-            found = list.begin();
-        }
-    } else {
-        if (found > list.begin() && found != list.end()) {
-            found--;
-        } else {
-            found = list.end() - 1;
-        }
-    }
-    auto tuneTo = found->selector;
-
-    mIsTuneCompleted = false;
-    auto task = [this, tuneTo, direction]() {
-        ALOGI("Performing scan %s", toString(direction).c_str());
-
-        lock_guard<mutex> lk(mMut);
-        tuneInternalLocked(tuneTo);
-    };
-    mThread.schedule(task, gDefaultDelay.scan);
-
-    return Result::OK;
-}
-
-Return<Result> Tuner::step(Direction direction, bool skipSubChannel) {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(mMut);
-    if (mIsClosed) return Result::NOT_INITIALIZED;
-
-    ALOGW_IF(!skipSubChannel, "can't step to next frequency without ignoring subChannel");
-
-    if (!utils::isAmFm(utils::getType(mCurrentProgram))) {
-        ALOGE("Can't step in anything else than AM/FM");
-        return Result::NOT_INITIALIZED;
-    }
-
-    if (!mIsAmfmConfigSet) {
-        ALOGW("AM/FM config not set");
-        return Result::INVALID_STATE;
-    }
-    mIsTuneCompleted = false;
-
-    auto task = [this, direction]() {
-        ALOGI("Performing step %s", toString(direction).c_str());
-
-        lock_guard<mutex> lk(mMut);
-
-        auto current = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY, 0);
-
-        if (direction == Direction::UP) {
-            current += mAmfmConfig.spacings[0];
-        } else {
-            current -= mAmfmConfig.spacings[0];
-        }
-
-        if (current > mAmfmConfig.upperLimit) current = mAmfmConfig.lowerLimit;
-        if (current < mAmfmConfig.lowerLimit) current = mAmfmConfig.upperLimit;
-
-        tuneInternalLocked(utils::make_selector(mAmfmConfig.type, current));
-    };
-    mThread.schedule(task, gDefaultDelay.step);
-
-    return Result::OK;
-}
-
-Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) {
-    ALOGV("%s(%d, %d)", __func__, channel, subChannel);
-    Band band;
-    {
-        lock_guard<mutex> lk(mMut);
-        band = mAmfmConfig.type;
-    }
-    return tuneByProgramSelector(utils::make_selector(band, channel, subChannel));
-}
-
-Return<Result> Tuner::tuneByProgramSelector(const ProgramSelector& sel) {
-    ALOGV("%s(%s)", __func__, toString(sel).c_str());
-    lock_guard<mutex> lk(mMut);
-    if (mIsClosed) return Result::NOT_INITIALIZED;
-
-    // checking if ProgramSelector is valid
-    auto programType = utils::getType(sel);
-    if (utils::isAmFm(programType)) {
-        if (!mIsAmfmConfigSet) {
-            ALOGW("AM/FM config not set");
-            return Result::INVALID_STATE;
-        }
-
-        auto freq = utils::getId(sel, IdentifierType::AMFM_FREQUENCY);
-        if (freq < mAmfmConfig.lowerLimit || freq > mAmfmConfig.upperLimit) {
-            return Result::INVALID_ARGUMENTS;
-        }
-    } else if (programType == ProgramType::DAB) {
-        if (!utils::hasId(sel, IdentifierType::DAB_SIDECC)) return Result::INVALID_ARGUMENTS;
-    } else if (programType == ProgramType::DRMO) {
-        if (!utils::hasId(sel, IdentifierType::DRMO_SERVICE_ID)) return Result::INVALID_ARGUMENTS;
-    } else if (programType == ProgramType::SXM) {
-        if (!utils::hasId(sel, IdentifierType::SXM_SERVICE_ID)) return Result::INVALID_ARGUMENTS;
-    } else {
-        return Result::INVALID_ARGUMENTS;
-    }
-
-    mIsTuneCompleted = false;
-    auto task = [this, sel]() {
-        lock_guard<mutex> lk(mMut);
-        tuneInternalLocked(sel);
-    };
-    mThread.schedule(task, gDefaultDelay.tune);
-
-    return Result::OK;
-}
-
-Return<Result> Tuner::cancel() {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(mMut);
-    if (mIsClosed) return Result::NOT_INITIALIZED;
-
-    mThread.cancelAll();
-    return Result::OK;
-}
-
-Return<Result> Tuner::cancelAnnouncement() {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(mMut);
-    if (mIsClosed) return Result::NOT_INITIALIZED;
-
-    return Result::OK;
-}
-
-Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) {
-    ALOGV("%s", __func__);
-    return getProgramInformation_1_1([&](Result result, const ProgramInfo& info) {
-        _hidl_cb(result, info.base);
-    });
-}
-
-Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(mMut);
-
-    if (mIsClosed) {
-        _hidl_cb(Result::NOT_INITIALIZED, {});
-    } else if (mIsTuneCompleted) {
-        _hidl_cb(Result::OK, mCurrentProgramInfo);
-    } else {
-        _hidl_cb(Result::NOT_INITIALIZED, makeDummyProgramInfo(mCurrentProgram));
-    }
-    return {};
-}
-
-Return<ProgramListResult> Tuner::startBackgroundScan() {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(mMut);
-    if (mIsClosed) return ProgramListResult::NOT_INITIALIZED;
-
-    return ProgramListResult::UNAVAILABLE;
-}
-
-Return<void> Tuner::getProgramList(const hidl_vec<VendorKeyValue>& vendorFilter,
-                                   getProgramList_cb _hidl_cb) {
-    ALOGV("%s(%s)", __func__, toString(vendorFilter).substr(0, 100).c_str());
-    lock_guard<mutex> lk(mMut);
-    if (mIsClosed) {
-        _hidl_cb(ProgramListResult::NOT_INITIALIZED, {});
-        return {};
-    }
-
-    auto list = mVirtualRadio.get().getProgramList();
-    ALOGD("returning a list of %zu programs", list.size());
-    _hidl_cb(ProgramListResult::OK, getProgramInfoVector(list, getHalRev()));
-    return {};
-}
-
-Return<Result> Tuner::setAnalogForced(bool isForced) {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(mMut);
-    if (mIsClosed) return Result::NOT_INITIALIZED;
-
-    mIsAnalogForced = isForced;
-    return Result::OK;
-}
-
-Return<void> Tuner::isAnalogForced(isAnalogForced_cb _hidl_cb) {
-    ALOGV("%s", __func__);
-    lock_guard<mutex> lk(mMut);
-
-    if (mIsClosed) {
-        _hidl_cb(Result::NOT_INITIALIZED, false);
-    } else {
-        _hidl_cb(Result::OK, mIsAnalogForced);
-    }
-    return {};
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
diff --git a/broadcastradio/1.1/default/Tuner.h b/broadcastradio/1.1/default/Tuner.h
deleted file mode 100644
index 07d3189..0000000
--- a/broadcastradio/1.1/default/Tuner.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H
-#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H
-
-#include "VirtualRadio.h"
-
-#include <android/hardware/broadcastradio/1.1/ITuner.h>
-#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
-#include <broadcastradio-utils/WorkerThread.h>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-struct Tuner : public ITuner {
-    Tuner(V1_0::Class classId, const sp<V1_0::ITunerCallback>& callback);
-
-    void forceClose();
-
-    // V1_1::ITuner methods
-    virtual Return<Result> setConfiguration(const V1_0::BandConfig& config) override;
-    virtual Return<void> getConfiguration(getConfiguration_cb _hidl_cb) override;
-    virtual Return<Result> scan(V1_0::Direction direction, bool skipSubChannel) override;
-    virtual Return<Result> step(V1_0::Direction direction, bool skipSubChannel) override;
-    virtual Return<Result> tune(uint32_t channel, uint32_t subChannel) override;
-    virtual Return<Result> tuneByProgramSelector(const ProgramSelector& program) override;
-    virtual Return<Result> cancel() override;
-    virtual Return<Result> cancelAnnouncement() override;
-    virtual Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override;
-    virtual Return<void> getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) override;
-    virtual Return<ProgramListResult> startBackgroundScan() override;
-    virtual Return<void> getProgramList(const hidl_vec<VendorKeyValue>& filter,
-                                        getProgramList_cb _hidl_cb) override;
-    virtual Return<Result> setAnalogForced(bool isForced) override;
-    virtual Return<void> isAnalogForced(isAnalogForced_cb _hidl_cb) override;
-
-   private:
-    std::mutex mMut;
-    WorkerThread mThread;
-    bool mIsClosed = false;
-
-    V1_0::Class mClassId;
-    const sp<V1_0::ITunerCallback> mCallback;
-    const sp<V1_1::ITunerCallback> mCallback1_1;
-
-    std::reference_wrapper<VirtualRadio> mVirtualRadio;
-    bool mIsAmfmConfigSet = false;
-    V1_0::BandConfig mAmfmConfig;
-    bool mIsTuneCompleted = false;
-    ProgramSelector mCurrentProgram = {};
-    ProgramInfo mCurrentProgramInfo = {};
-    std::atomic<bool> mIsAnalogForced;
-
-    utils::HalRevision getHalRev() const;
-    void tuneInternalLocked(const ProgramSelector& sel);
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H
diff --git a/broadcastradio/1.1/default/VirtualProgram.cpp b/broadcastradio/1.1/default/VirtualProgram.cpp
deleted file mode 100644
index 7977391..0000000
--- a/broadcastradio/1.1/default/VirtualProgram.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include "VirtualProgram.h"
-
-#include <broadcastradio-utils/Utils.h>
-
-#include "resources.h"
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-using std::vector;
-
-using V1_0::MetaData;
-using V1_0::MetadataKey;
-using V1_0::MetadataType;
-using utils::HalRevision;
-
-static MetaData createDemoBitmap(MetadataKey key, HalRevision halRev) {
-    MetaData bmp = {MetadataType::INT, key, resources::demoPngId, {}, {}, {}};
-    if (halRev < HalRevision::V1_1) {
-        bmp.type = MetadataType::RAW;
-        bmp.intValue = 0;
-        bmp.rawValue = hidl_vec<uint8_t>(resources::demoPng, std::end(resources::demoPng));
-    }
-    return bmp;
-}
-
-ProgramInfo VirtualProgram::getProgramInfo(HalRevision halRev) const {
-    ProgramInfo info11 = {};
-    auto& info10 = info11.base;
-
-    utils::getLegacyChannel(selector, &info10.channel, &info10.subChannel);
-    info11.selector = selector;
-    info10.tuned = true;
-    info10.stereo = true;
-    info10.digital = utils::isDigital(selector);
-    info10.signalStrength = info10.digital ? 100 : 80;
-
-    info10.metadata = hidl_vec<MetaData>({
-        {MetadataType::TEXT, MetadataKey::RDS_PS, {}, {}, programName, {}},
-        {MetadataType::TEXT, MetadataKey::TITLE, {}, {}, songTitle, {}},
-        {MetadataType::TEXT, MetadataKey::ARTIST, {}, {}, songArtist, {}},
-        createDemoBitmap(MetadataKey::ICON, halRev),
-        createDemoBitmap(MetadataKey::ART, halRev),
-    });
-
-    info11.vendorInfo = hidl_vec<VendorKeyValue>({
-        {"com.google.dummy", "dummy"},
-        {"com.google.dummy.VirtualProgram", std::to_string(reinterpret_cast<uintptr_t>(this))},
-    });
-
-    return info11;
-}
-
-// Defining order on virtual programs, how they appear on band.
-// It's mostly for default implementation purposes, may not be complete or correct.
-bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs) {
-    auto& l = lhs.selector;
-    auto& r = rhs.selector;
-
-    // Two programs with the same primaryId is considered the same.
-    if (l.programType != r.programType) return l.programType < r.programType;
-    if (l.primaryId.type != r.primaryId.type) return l.primaryId.type < r.primaryId.type;
-    if (l.primaryId.value != r.primaryId.value) return l.primaryId.value < r.primaryId.value;
-
-    // A little exception for HD Radio subchannel - we check secondary ID too.
-    if (utils::hasId(l, IdentifierType::HD_SUBCHANNEL) &&
-        utils::hasId(r, IdentifierType::HD_SUBCHANNEL)) {
-        return utils::getId(l, IdentifierType::HD_SUBCHANNEL) <
-               utils::getId(r, IdentifierType::HD_SUBCHANNEL);
-    }
-
-    return false;
-}
-
-vector<ProgramInfo> getProgramInfoVector(const vector<VirtualProgram>& vec, HalRevision halRev) {
-    vector<ProgramInfo> out;
-    out.reserve(vec.size());
-    for (auto&& program : vec) {
-        out.push_back(program.getProgramInfo(halRev));
-    }
-    return out;
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
diff --git a/broadcastradio/1.1/default/VirtualProgram.h b/broadcastradio/1.1/default/VirtualProgram.h
deleted file mode 100644
index a14830d..0000000
--- a/broadcastradio/1.1/default/VirtualProgram.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALPROGRAM_H
-#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALPROGRAM_H
-
-#include <android/hardware/broadcastradio/1.1/types.h>
-#include <broadcastradio-utils/Utils.h>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-/**
- * A radio program mock.
- *
- * This represents broadcast waves flying over the air,
- * not an entry for a captured station in the radio tuner memory.
- */
-struct VirtualProgram {
-    ProgramSelector selector;
-
-    std::string programName = "";
-    std::string songArtist = "";
-    std::string songTitle = "";
-
-    ProgramInfo getProgramInfo(utils::HalRevision halRev) const;
-
-    friend bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs);
-};
-
-std::vector<ProgramInfo> getProgramInfoVector(const std::vector<VirtualProgram>& vec,
-                                              utils::HalRevision halRev);
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALPROGRAM_H
diff --git a/broadcastradio/1.1/default/VirtualRadio.cpp b/broadcastradio/1.1/default/VirtualRadio.cpp
deleted file mode 100644
index 36d47a9..0000000
--- a/broadcastradio/1.1/default/VirtualRadio.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "BroadcastRadioDefault.VirtualRadio"
-//#define LOG_NDEBUG 0
-
-#include "VirtualRadio.h"
-
-#include <broadcastradio-utils/Utils.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-using V1_0::Band;
-using V1_0::Class;
-
-using std::lock_guard;
-using std::move;
-using std::mutex;
-using std::vector;
-
-using utils::make_selector;
-
-static const vector<VirtualProgram> gInitialFmPrograms{
-    {make_selector(Band::FM, 94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
-    {make_selector(Band::FM, 96500), "KOIT", "Celine Dion", "All By Myself"},
-    {make_selector(Band::FM, 97300), "Alice@97.3", "Drops of Jupiter", "Train"},
-    {make_selector(Band::FM, 99700), "99.7 Now!", "The Chainsmokers", "Closer"},
-    {make_selector(Band::FM, 101300), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"},
-    {make_selector(Band::FM, 103700), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"},
-    {make_selector(Band::FM, 106100), "106 KMEL", "Drake", "Marvins Room"},
-};
-
-static VirtualRadio gEmptyRadio({});
-static VirtualRadio gFmRadio(gInitialFmPrograms);
-
-VirtualRadio::VirtualRadio(const vector<VirtualProgram> initialList) : mPrograms(initialList) {}
-
-vector<VirtualProgram> VirtualRadio::getProgramList() {
-    lock_guard<mutex> lk(mMut);
-    return mPrograms;
-}
-
-bool VirtualRadio::getProgram(const ProgramSelector& selector, VirtualProgram& programOut) {
-    lock_guard<mutex> lk(mMut);
-    for (auto&& program : mPrograms) {
-        if (utils::tunesTo(selector, program.selector)) {
-            programOut = program;
-            return true;
-        }
-    }
-    return false;
-}
-
-VirtualRadio& getRadio(V1_0::Class classId) {
-    switch (classId) {
-        case Class::AM_FM:
-            return getFmRadio();
-        case Class::SAT:
-            return getSatRadio();
-        case Class::DT:
-            return getDigitalRadio();
-        default:
-            ALOGE("Invalid class ID");
-            return gEmptyRadio;
-    }
-}
-
-VirtualRadio& getAmRadio() {
-    return gEmptyRadio;
-}
-
-VirtualRadio& getFmRadio() {
-    return gFmRadio;
-}
-
-VirtualRadio& getSatRadio() {
-    return gEmptyRadio;
-}
-
-VirtualRadio& getDigitalRadio() {
-    return gEmptyRadio;
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
diff --git a/broadcastradio/1.1/default/VirtualRadio.h b/broadcastradio/1.1/default/VirtualRadio.h
deleted file mode 100644
index 3c7ae5c..0000000
--- a/broadcastradio/1.1/default/VirtualRadio.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALRADIO_H
-#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALRADIO_H
-
-#include "VirtualProgram.h"
-
-#include <mutex>
-#include <vector>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-/**
- * A radio frequency space mock.
- *
- * This represents all broadcast waves in the air for a given radio technology,
- * not a captured station list in the radio tuner memory.
- *
- * It's meant to abstract out radio content from default tuner implementation.
- */
-class VirtualRadio {
-   public:
-    VirtualRadio(const std::vector<VirtualProgram> initialList);
-
-    std::vector<VirtualProgram> getProgramList();
-    bool getProgram(const ProgramSelector& selector, VirtualProgram& program);
-
-   private:
-    std::mutex mMut;
-    std::vector<VirtualProgram> mPrograms;
-};
-
-/**
- * Get virtual radio space for a given radio class.
- *
- * As a space, each virtual radio always exists. For example, DAB frequencies
- * exists in US, but contains no programs.
- *
- * The lifetime of the virtual radio space is virtually infinite, but for the
- * needs of default implementation, it's bound with the lifetime of default
- * implementation process.
- *
- * Internally, it's a static object, so trying to access the reference during
- * default implementation library unloading may result in segmentation fault.
- * It's unlikely for testing purposes.
- *
- * @param classId A class of radio technology.
- * @return A reference to virtual radio space for a given technology.
- */
-VirtualRadio& getRadio(V1_0::Class classId);
-
-VirtualRadio& getAmRadio();
-VirtualRadio& getFmRadio();
-VirtualRadio& getSatRadio();
-VirtualRadio& getDigitalRadio();
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALRADIO_H
diff --git a/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc b/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc
deleted file mode 100644
index 7c57135..0000000
--- a/broadcastradio/1.1/default/android.hardware.broadcastradio@1.1-service.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service broadcastradio-hal /vendor/bin/hw/android.hardware.broadcastradio@1.1-service
-    class hal
-    user audioserver
-    group audio
diff --git a/broadcastradio/1.1/default/resources.h b/broadcastradio/1.1/default/resources.h
deleted file mode 100644
index b7e709f..0000000
--- a/broadcastradio/1.1/default/resources.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_RESOURCES_H
-#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_RESOURCES_H
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-namespace resources {
-
-constexpr int32_t demoPngId = 123456;
-constexpr uint8_t demoPng[] = {
-    0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44,
-    0x52, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x08, 0x02, 0x00, 0x00, 0x00, 0x25,
-    0x0b, 0xe6, 0x89, 0x00, 0x00, 0x00, 0x5d, 0x49, 0x44, 0x41, 0x54, 0x68, 0xde, 0xed, 0xd9,
-    0xc1, 0x09, 0x00, 0x30, 0x08, 0x04, 0xc1, 0x33, 0xfd, 0xf7, 0x6c, 0x6a, 0xc8, 0x23, 0x04,
-    0xc9, 0x6c, 0x01, 0xc2, 0x20, 0xbe, 0x4c, 0x86, 0x57, 0x49, 0xba, 0xfb, 0xd6, 0xf4, 0xba,
-    0x3e, 0x7f, 0x4d, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8f, 0x00, 0xbd, 0xce, 0x7f,
-    0xc0, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xb8, 0x0d, 0x32, 0xd4, 0x0c, 0x77, 0xbd,
-    0xfb, 0xc1, 0xce, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
-
-}  // namespace resources
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_RESOURCES_H
diff --git a/broadcastradio/1.1/default/service.cpp b/broadcastradio/1.1/default/service.cpp
deleted file mode 100644
index f8af0b7..0000000
--- a/broadcastradio/1.1/default/service.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "BroadcastRadioDefault.service"
-
-#include <android-base/logging.h>
-#include <hidl/HidlTransportSupport.h>
-
-#include "BroadcastRadioFactory.h"
-
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-using android::hardware::broadcastradio::V1_1::implementation::BroadcastRadioFactory;
-
-int main(int /* argc */, char** /* argv */) {
-    configureRpcThreadpool(4, true);
-
-    BroadcastRadioFactory broadcastRadioFactory;
-    auto status = broadcastRadioFactory.registerAsService();
-    CHECK_EQ(status, android::OK) << "Failed to register Broadcast Radio HAL implementation";
-
-    joinRpcThreadpool();
-    return 1;  // joinRpcThreadpool shouldn't exit
-}
diff --git a/broadcastradio/1.1/tests/Android.bp b/broadcastradio/1.1/tests/Android.bp
deleted file mode 100644
index fa1fd94..0000000
--- a/broadcastradio/1.1/tests/Android.bp
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_test {
-    name: "android.hardware.broadcastradio@1.1-utils-tests",
-    vendor: true,
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-    ],
-    srcs: [
-        "WorkerThread_test.cpp",
-    ],
-    static_libs: ["android.hardware.broadcastradio@1.1-utils-lib"],
-}
diff --git a/broadcastradio/1.1/tests/OWNERS b/broadcastradio/1.1/tests/OWNERS
deleted file mode 100644
index aa5ce82..0000000
--- a/broadcastradio/1.1/tests/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# Automotive team
-egranata@google.com
-keunyoung@google.com
-twasilczyk@google.com
-
-# VTS team
-ryanjcampbell@google.com
-yim@google.com
diff --git a/broadcastradio/1.1/utils/Android.bp b/broadcastradio/1.1/utils/Android.bp
deleted file mode 100644
index e80d133..0000000
--- a/broadcastradio/1.1/utils/Android.bp
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_library_static {
-    name: "android.hardware.broadcastradio@1.1-utils-lib",
-    vendor_available: true,
-    relative_install_path: "hw",
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-    ],
-    srcs: [
-        "Utils.cpp",
-        "WorkerThread.cpp",
-    ],
-    export_include_dirs: ["include"],
-    shared_libs: [
-        "android.hardware.broadcastradio@1.1",
-    ],
-}
diff --git a/broadcastradio/1.1/utils/OWNERS b/broadcastradio/1.1/utils/OWNERS
deleted file mode 100644
index 0c27b71..0000000
--- a/broadcastradio/1.1/utils/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Automotive team
-egranata@google.com
-keunyoung@google.com
-twasilczyk@google.com
diff --git a/broadcastradio/1.1/utils/Utils.cpp b/broadcastradio/1.1/utils/Utils.cpp
deleted file mode 100644
index 4dd6b13..0000000
--- a/broadcastradio/1.1/utils/Utils.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "BroadcastRadioDefault.utils"
-//#define LOG_NDEBUG 0
-
-#include <broadcastradio-utils/Utils.h>
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace utils {
-
-using V1_0::Band;
-
-static bool isCompatibleProgramType(const uint32_t ia, const uint32_t ib) {
-    auto a = static_cast<ProgramType>(ia);
-    auto b = static_cast<ProgramType>(ib);
-
-    if (a == b) return true;
-    if (a == ProgramType::AM && b == ProgramType::AM_HD) return true;
-    if (a == ProgramType::AM_HD && b == ProgramType::AM) return true;
-    if (a == ProgramType::FM && b == ProgramType::FM_HD) return true;
-    if (a == ProgramType::FM_HD && b == ProgramType::FM) return true;
-    return false;
-}
-
-static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
-                       const IdentifierType type) {
-    return hasId(a, type) && hasId(b, type);
-}
-
-static bool anyHaveId(const ProgramSelector& a, const ProgramSelector& b,
-                      const IdentifierType type) {
-    return hasId(a, type) || hasId(b, type);
-}
-
-static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
-                         const IdentifierType type) {
-    if (!bothHaveId(a, b, type)) return false;
-    /* We should check all Ids of a given type (ie. other AF),
-     * but it doesn't matter for default implementation.
-     */
-    auto aId = getId(a, type);
-    auto bId = getId(b, type);
-    return aId == bId;
-}
-
-bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
-    if (!isCompatibleProgramType(a.programType, b.programType)) return false;
-
-    auto type = getType(a);
-
-    switch (type) {
-        case ProgramType::AM:
-        case ProgramType::AM_HD:
-        case ProgramType::FM:
-        case ProgramType::FM_HD:
-            if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
-
-            // if HD Radio subchannel is specified, it must match
-            if (anyHaveId(a, b, IdentifierType::HD_SUBCHANNEL)) {
-                // missing subchannel (analog) is an equivalent of first subchannel (MPS)
-                auto aCh = getId(a, IdentifierType::HD_SUBCHANNEL, 0);
-                auto bCh = getId(b, IdentifierType::HD_SUBCHANNEL, 0);
-                if (aCh != bCh) return false;
-            }
-
-            if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
-
-            return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
-        case ProgramType::DAB:
-            return haveEqualIds(a, b, IdentifierType::DAB_SIDECC);
-        case ProgramType::DRMO:
-            return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
-        case ProgramType::SXM:
-            if (anyHaveId(a, b, IdentifierType::SXM_SERVICE_ID)) {
-                return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
-            }
-            return haveEqualIds(a, b, IdentifierType::SXM_CHANNEL);
-        default:  // includes all vendor types
-            ALOGW("Unsupported program type: %s", toString(type).c_str());
-            return false;
-    }
-}
-
-ProgramType getType(const ProgramSelector& sel) {
-    return static_cast<ProgramType>(sel.programType);
-}
-
-bool isAmFm(const ProgramType type) {
-    switch (type) {
-        case ProgramType::AM:
-        case ProgramType::FM:
-        case ProgramType::AM_HD:
-        case ProgramType::FM_HD:
-            return true;
-        default:
-            return false;
-    }
-}
-
-bool isAm(const Band band) {
-    return band == Band::AM || band == Band::AM_HD;
-}
-
-bool isFm(const Band band) {
-    return band == Band::FM || band == Band::FM_HD;
-}
-
-bool hasId(const ProgramSelector& sel, const IdentifierType type) {
-    auto itype = static_cast<uint32_t>(type);
-    if (sel.primaryId.type == itype) return true;
-    // not optimal, but we don't care in default impl
-    for (auto&& id : sel.secondaryIds) {
-        if (id.type == itype) return true;
-    }
-    return false;
-}
-
-uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
-    auto itype = static_cast<uint32_t>(type);
-    if (sel.primaryId.type == itype) return sel.primaryId.value;
-    // not optimal, but we don't care in default impl
-    for (auto&& id : sel.secondaryIds) {
-        if (id.type == itype) return id.value;
-    }
-    ALOGW("Identifier %s not found", toString(type).c_str());
-    return 0;
-}
-
-uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
-    if (!hasId(sel, type)) return defval;
-    return getId(sel, type);
-}
-
-ProgramSelector make_selector(Band band, uint32_t channel, uint32_t subChannel) {
-    ProgramSelector sel = {};
-
-    ALOGW_IF((subChannel > 0) && (band == Band::AM || band == Band::FM),
-             "got subChannel for non-HD AM/FM");
-
-    // we can't use ProgramType::AM_HD or FM_HD, because we don't know HD station ID
-    ProgramType type;
-    if (isAm(band)) {
-        type = ProgramType::AM;
-    } else if (isFm(band)) {
-        type = ProgramType::FM;
-    } else {
-        LOG_ALWAYS_FATAL("Unsupported band: %s", toString(band).c_str());
-    }
-
-    sel.programType = static_cast<uint32_t>(type);
-    sel.primaryId.type = static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY);
-    sel.primaryId.value = channel;
-    if (subChannel > 0) {
-        /* stating sub channel for AM/FM channel does not give any guarantees,
-         * but we can't do much more without HD station ID
-         *
-         * The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based.
-         */
-        sel.secondaryIds = hidl_vec<ProgramIdentifier>{
-            {static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL), subChannel - 1},
-        };
-    }
-
-    return sel;
-}
-
-bool getLegacyChannel(const ProgramSelector& sel, uint32_t* channelOut, uint32_t* subChannelOut) {
-    if (channelOut) *channelOut = 0;
-    if (subChannelOut) *subChannelOut = 0;
-    if (isAmFm(getType(sel))) {
-        if (channelOut) *channelOut = getId(sel, IdentifierType::AMFM_FREQUENCY);
-        if (subChannelOut && hasId(sel, IdentifierType::HD_SUBCHANNEL)) {
-            // The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based.
-            *subChannelOut = getId(sel, IdentifierType::HD_SUBCHANNEL) + 1;
-        }
-        return true;
-    }
-    return false;
-}
-
-bool isDigital(const ProgramSelector& sel) {
-    switch (getType(sel)) {
-        case ProgramType::AM:
-        case ProgramType::FM:
-            return false;
-        default:
-            // VENDOR might not be digital, but it doesn't matter for default impl.
-            return true;
-    }
-}
-
-}  // namespace utils
-}  // namespace V1_1
-
-namespace V1_0 {
-
-bool operator==(const BandConfig& l, const BandConfig& r) {
-    if (l.type != r.type) return false;
-    if (l.antennaConnected != r.antennaConnected) return false;
-    if (l.lowerLimit != r.lowerLimit) return false;
-    if (l.upperLimit != r.upperLimit) return false;
-    if (l.spacings != r.spacings) return false;
-    if (V1_1::utils::isAm(l.type)) {
-        return l.ext.am == r.ext.am;
-    } else if (V1_1::utils::isFm(l.type)) {
-        return l.ext.fm == r.ext.fm;
-    } else {
-        ALOGW("Unsupported band config type: %s", toString(l.type).c_str());
-        return false;
-    }
-}
-
-}  // namespace V1_0
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
diff --git a/broadcastradio/1.1/utils/include/broadcastradio-utils/Utils.h b/broadcastradio/1.1/utils/include/broadcastradio-utils/Utils.h
deleted file mode 100644
index 24c60ee..0000000
--- a/broadcastradio/1.1/utils/include/broadcastradio-utils/Utils.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
-#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
-
-#include <android/hardware/broadcastradio/1.1/types.h>
-#include <chrono>
-#include <queue>
-#include <thread>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace utils {
-
-// TODO(b/64115813): move it out from frameworks/base/services/core/jni/BroadcastRadio/types.h
-enum class HalRevision : uint32_t {
-    V1_0 = 1,
-    V1_1,
-};
-
-/**
- * Checks, if {@code pointer} tunes to {@channel}.
- *
- * For example, having a channel {AMFM_FREQUENCY = 103.3}:
- * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 0} can tune to this channel;
- * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 1} can't.
- *
- * @param pointer selector we're trying to match against channel.
- * @param channel existing channel.
- */
-bool tunesTo(const ProgramSelector& pointer, const ProgramSelector& channel);
-
-ProgramType getType(const ProgramSelector& sel);
-bool isAmFm(const ProgramType type);
-
-bool isAm(const V1_0::Band band);
-bool isFm(const V1_0::Band band);
-
-bool hasId(const ProgramSelector& sel, const IdentifierType type);
-
-/**
- * Returns ID (either primary or secondary) for a given program selector.
- *
- * If the selector does not contain given type, returns 0 and emits a warning.
- */
-uint64_t getId(const ProgramSelector& sel, const IdentifierType type);
-
-/**
- * Returns ID (either primary or secondary) for a given program selector.
- *
- * If the selector does not contain given type, returns default value.
- */
-uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval);
-
-ProgramSelector make_selector(V1_0::Band band, uint32_t channel, uint32_t subChannel = 0);
-
-bool getLegacyChannel(const ProgramSelector& sel, uint32_t* channelOut, uint32_t* subChannelOut);
-
-bool isDigital(const ProgramSelector& sel);
-
-}  // namespace utils
-}  // namespace V1_1
-
-namespace V1_0 {
-
-bool operator==(const BandConfig& l, const BandConfig& r);
-
-}  // namespace V1_0
-
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
diff --git a/broadcastradio/1.1/utils/include/broadcastradio-utils/WorkerThread.h b/broadcastradio/1.1/utils/include/broadcastradio-utils/WorkerThread.h
deleted file mode 100644
index 635876f..0000000
--- a/broadcastradio/1.1/utils/include/broadcastradio-utils/WorkerThread.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_WORKERTHREAD_H
-#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_WORKERTHREAD_H
-
-#include <chrono>
-#include <queue>
-#include <thread>
-
-namespace android {
-
-class WorkerThread {
-   public:
-    WorkerThread();
-    virtual ~WorkerThread();
-
-    void schedule(std::function<void()> task, std::chrono::milliseconds delay);
-    void cancelAll();
-
-   private:
-    struct Task {
-        std::chrono::time_point<std::chrono::steady_clock> when;
-        std::function<void()> what;
-    };
-    friend bool operator<(const Task& lhs, const Task& rhs);
-
-    std::atomic<bool> mIsTerminating;
-    std::mutex mMut;
-    std::condition_variable mCond;
-    std::thread mThread;
-    std::priority_queue<Task> mTasks;
-
-    void threadLoop();
-};
-
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_WORKERTHREAD_H
diff --git a/broadcastradio/1.1/vts/OWNERS b/broadcastradio/1.1/vts/OWNERS
index aa5ce82..7736681 100644
--- a/broadcastradio/1.1/vts/OWNERS
+++ b/broadcastradio/1.1/vts/OWNERS
@@ -4,5 +4,5 @@
 twasilczyk@google.com
 
 # VTS team
-ryanjcampbell@google.com
+yuexima@google.com
 yim@google.com
diff --git a/broadcastradio/1.1/vts/functional/Android.bp b/broadcastradio/1.1/vts/functional/Android.bp
index 4b93cbc..27ae4e9 100644
--- a/broadcastradio/1.1/vts/functional/Android.bp
+++ b/broadcastradio/1.1/vts/functional/Android.bp
@@ -21,8 +21,9 @@
     static_libs: [
         "android.hardware.broadcastradio@1.0",
         "android.hardware.broadcastradio@1.1",
-        "android.hardware.broadcastradio@1.1-utils-lib",
-        "android.hardware.broadcastradio@1.1-vts-utils-lib",
+        "android.hardware.broadcastradio@1.2",  // common-utils-lib dependency
+        "android.hardware.broadcastradio@common-utils-1x-lib",
+        "android.hardware.broadcastradio@vts-utils-lib",
         "libgmock",
     ],
 }
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
index a46378e..823d14c 100644
--- a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
+++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -17,15 +17,16 @@
 #define LOG_TAG "broadcastradio.vts"
 
 #include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
 #include <android/hardware/broadcastradio/1.1/ITuner.h>
 #include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
 #include <android/hardware/broadcastradio/1.1/types.h>
-#include <android-base/logging.h>
-#include <broadcastradio-utils/Utils.h>
+#include <broadcastradio-utils-1x/Utils.h>
 #include <broadcastradio-vts-utils/call-barrier.h>
 #include <broadcastradio-vts-utils/mock-timeout.h>
+#include <broadcastradio-vts-utils/pointer-utils.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
 #include <gmock/gmock.h>
@@ -56,8 +57,7 @@
 using V1_0::MetadataKey;
 using V1_0::MetadataType;
 
-using std::chrono::steady_clock;
-using std::this_thread::sleep_for;
+using broadcastradio::vts::clearAndWait;
 
 static constexpr auto kConfigTimeout = 10s;
 static constexpr auto kConnectModuleTimeout = 1s;
@@ -115,27 +115,6 @@
     hidl_vec<BandConfig> mBands;
 };
 
-/**
- * Clears strong pointer and waits until the object gets destroyed.
- *
- * @param ptr The pointer to get cleared.
- * @param timeout Time to wait for other references.
- */
-template <typename T>
-static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) {
-    wp<T> wptr = ptr;
-    ptr.clear();
-    auto limit = steady_clock::now() + timeout;
-    while (wptr.promote() != nullptr) {
-        constexpr auto step = 10ms;
-        if (steady_clock::now() + step > limit) {
-            FAIL() << "Pointer was not released within timeout";
-            break;
-        }
-        sleep_for(step);
-    }
-}
-
 void BroadcastRadioHalTest::SetUp() {
     radioClass = GetParam();
 
@@ -525,6 +504,98 @@
     ASSERT_FALSE(forced);
 }
 
+static void verifyIdentifier(const ProgramIdentifier& id) {
+    EXPECT_NE(id.type, 0u);
+    auto val = id.value;
+
+    switch (static_cast<IdentifierType>(id.type)) {
+        case IdentifierType::AMFM_FREQUENCY:
+        case IdentifierType::DAB_FREQUENCY:
+        case IdentifierType::DRMO_FREQUENCY:
+            EXPECT_GT(val, 100u) << "Expected f > 100kHz";
+            EXPECT_LT(val, 10000000u) << "Expected f < 10GHz";
+            break;
+        case IdentifierType::RDS_PI:
+            EXPECT_GT(val, 0u);
+            EXPECT_LE(val, 0xFFFFu) << "Expected 16bit id";
+            break;
+        case IdentifierType::HD_STATION_ID_EXT: {
+            auto stationId = val & 0xFFFFFFFF;  // 32bit
+            val >>= 32;
+            auto subchannel = val & 0xF;  // 4bit
+            val >>= 4;
+            auto freq = val & 0x3FFFF;  // 18bit
+            EXPECT_GT(stationId, 0u);
+            EXPECT_LT(subchannel, 8u) << "Expected ch < 8";
+            EXPECT_GT(freq, 100u) << "Expected f > 100kHz";
+            EXPECT_LT(freq, 10000000u) << "Expected f < 10GHz";
+            break;
+        }
+        case IdentifierType::HD_SUBCHANNEL:
+            EXPECT_LT(val, 8u) << "Expected ch < 8";
+            break;
+        case IdentifierType::DAB_SIDECC: {
+            auto sid = val & 0xFFFF;  // 16bit
+            val >>= 16;
+            auto ecc = val & 0xFF;  // 8bit
+            EXPECT_NE(sid, 0u);
+            EXPECT_GE(ecc, 0xA0u) << "Invalid ECC, see ETSI TS 101 756 V2.1.1";
+            EXPECT_LE(ecc, 0xF6u) << "Invalid ECC, see ETSI TS 101 756 V2.1.1";
+            break;
+        }
+        case IdentifierType::DAB_ENSEMBLE:
+            EXPECT_GT(val, 0u);
+            EXPECT_LE(val, 0xFFFFu) << "Expected 16bit id";
+            break;
+        case IdentifierType::DAB_SCID:
+            EXPECT_GT(val, 0xFu) << "Expected 12bit SCId (not 4bit SCIdS)";
+            EXPECT_LE(val, 0xFFFu) << "Expected 12bit id";
+            break;
+        case IdentifierType::DRMO_SERVICE_ID:
+            EXPECT_GT(val, 0u);
+            EXPECT_LE(val, 0xFFFFFFu) << "Expected 24bit id";
+            break;
+        case IdentifierType::DRMO_MODULATION:
+            EXPECT_GE(val, static_cast<uint32_t>(Modulation::AM));
+            EXPECT_LE(val, static_cast<uint32_t>(Modulation::FM));
+            break;
+        case IdentifierType::SXM_SERVICE_ID:
+            EXPECT_GT(val, 0u);
+            EXPECT_LE(val, 0xFFFFFFFFu) << "Expected 32bit id";
+            break;
+        case IdentifierType::SXM_CHANNEL:
+            EXPECT_LT(val, 1000u);
+            break;
+        case IdentifierType::VENDOR_PRIMARY_START:
+        case IdentifierType::VENDOR_PRIMARY_END:
+            // skip
+            break;
+    }
+}
+
+/**
+ * Test ProgramIdentifier format.
+ *
+ * Verifies that:
+ * - values of ProgramIdentifier match their definitions at IdentifierType.
+ */
+TEST_P(BroadcastRadioHalTest, VerifyIdentifiersFormat) {
+    if (skipped) return;
+    ASSERT_TRUE(openTuner());
+
+    do {
+        auto getCb = [&](const hidl_vec<ProgramInfo>& list) {
+            for (auto&& program : list) {
+                verifyIdentifier(program.selector.primaryId);
+                for (auto&& id : program.selector.secondaryIds) {
+                    verifyIdentifier(id);
+                }
+            }
+        };
+        getProgramList(getCb);
+    } while (nextBand());
+}
+
 INSTANTIATE_TEST_CASE_P(BroadcastRadioHalTestCases, BroadcastRadioHalTest,
                         ::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
 
diff --git a/broadcastradio/1.1/vts/utils/Android.bp b/broadcastradio/1.1/vts/utils/Android.bp
deleted file mode 100644
index 0c7e2a4..0000000
--- a/broadcastradio/1.1/vts/utils/Android.bp
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// Copyright (C) 2017 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-cc_library_static {
-    name: "android.hardware.broadcastradio@1.1-vts-utils-lib",
-    srcs: [
-        "call-barrier.cpp",
-    ],
-    export_include_dirs: ["include"],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-    ],
-}
diff --git a/broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h b/broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h
deleted file mode 100644
index b0ce088..0000000
--- a/broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT
-#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT
-
-#include <gmock/gmock.h>
-#include <thread>
-
-/**
- * Common helper objects for gmock timeout extension.
- *
- * INTERNAL IMPLEMENTATION - don't use in user code.
- */
-#define EGMOCK_TIMEOUT_METHOD_DEF_(Method, ...) \
-    std::atomic<bool> egmock_called_##Method;   \
-    std::mutex egmock_mut_##Method;             \
-    std::condition_variable egmock_cond_##Method;
-
-/**
- * Common method body for gmock timeout extension.
- *
- * INTERNAL IMPLEMENTATION - don't use in user code.
- */
-#define EGMOCK_TIMEOUT_METHOD_BODY_(Method, ...)             \
-    auto ret = egmock_##Method(__VA_ARGS__);                 \
-    {                                                        \
-        std::lock_guard<std::mutex> lk(egmock_mut_##Method); \
-        egmock_called_##Method = true;                       \
-        egmock_cond_##Method.notify_all();                   \
-    }                                                        \
-    return ret;
-
-/**
- * Gmock MOCK_METHOD0 timeout-capable extension.
- */
-#define MOCK_TIMEOUT_METHOD0(Method, ...)       \
-    MOCK_METHOD0(egmock_##Method, __VA_ARGS__); \
-    EGMOCK_TIMEOUT_METHOD_DEF_(Method);         \
-    virtual GMOCK_RESULT_(, __VA_ARGS__) Method() { EGMOCK_TIMEOUT_METHOD_BODY_(Method); }
-
-/**
- * Gmock MOCK_METHOD1 timeout-capable extension.
- */
-#define MOCK_TIMEOUT_METHOD1(Method, ...)                                                 \
-    MOCK_METHOD1(egmock_##Method, __VA_ARGS__);                                           \
-    EGMOCK_TIMEOUT_METHOD_DEF_(Method);                                                   \
-    virtual GMOCK_RESULT_(, __VA_ARGS__) Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1) { \
-        EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1);                                   \
-    }
-
-/**
- * Gmock MOCK_METHOD2 timeout-capable extension.
- */
-#define MOCK_TIMEOUT_METHOD2(Method, ...)                                                        \
-    MOCK_METHOD2(egmock_##Method, __VA_ARGS__);                                                  \
-    EGMOCK_TIMEOUT_METHOD_DEF_(Method);                                                          \
-    virtual GMOCK_RESULT_(, __VA_ARGS__)                                                         \
-        Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1, GMOCK_ARG_(, 2, __VA_ARGS__) egmock_a2) { \
-        EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1, egmock_a2);                               \
-    }
-
-/**
- * Gmock EXPECT_CALL timeout-capable extension.
- *
- * It has slightly different syntax from the original macro, to make method name accessible.
- * So, instead of typing
- *     EXPECT_CALL(account, charge(100, Currency::USD));
- * you need to inline arguments
- *     EXPECT_TIMEOUT_CALL(account, charge, 100, Currency::USD);
- */
-#define EXPECT_TIMEOUT_CALL(obj, Method, ...) \
-    (obj).egmock_called_##Method = false;     \
-    EXPECT_CALL(obj, egmock_##Method(__VA_ARGS__))
-
-/**
- * Waits for an earlier EXPECT_TIMEOUT_CALL to execute.
- *
- * It does not fully support special constraints of the EXPECT_CALL clause, just proceeds when the
- * first call to a given method comes. For example, in the following code:
- *     EXPECT_TIMEOUT_CALL(account, charge, 100, _);
- *     account.charge(50, Currency::USD);
- *     EXPECT_TIMEOUT_CALL_WAIT(account, charge, 500ms);
- * the wait clause will just continue, as the charge method was called.
- *
- * @param obj object for a call
- * @param Method the method to wait for
- * @param timeout the maximum time for waiting
- */
-#define EXPECT_TIMEOUT_CALL_WAIT(obj, Method, timeout)                      \
-    {                                                                       \
-        std::unique_lock<std::mutex> lk((obj).egmock_mut_##Method);         \
-        if (!(obj).egmock_called_##Method) {                                \
-            auto status = (obj).egmock_cond_##Method.wait_for(lk, timeout); \
-            EXPECT_EQ(std::cv_status::no_timeout, status);                  \
-        }                                                                   \
-    }
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT
diff --git a/broadcastradio/1.2/Android.bp b/broadcastradio/1.2/Android.bp
new file mode 100644
index 0000000..40eb4e0
--- /dev/null
+++ b/broadcastradio/1.2/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.broadcastradio@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IBroadcastRadioFactory.hal",
+        "ITuner.hal",
+        "ITunerCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.broadcastradio@1.0",
+        "android.hardware.broadcastradio@1.1",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "IdentifierType",
+    ],
+    gen_java: false,
+}
+
diff --git a/broadcastradio/1.2/IBroadcastRadioFactory.hal b/broadcastradio/1.2/IBroadcastRadioFactory.hal
new file mode 100644
index 0000000..29f6ab3
--- /dev/null
+++ b/broadcastradio/1.2/IBroadcastRadioFactory.hal
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio@1.2;
+
+import @1.1::IBroadcastRadioFactory;
+
+/**
+ * To use 1.2 features you must cast specific interfaces returned from the
+ * 1.0 HAL. For example V1_0::IBroadcastRadio::openTuner() returns V1_0::ITuner,
+ * which can be cast with V1_2::ITuner::castFrom() call.
+ *
+ * The 1.2 server must always return the 1.2 version of specific interface.
+ */
+interface IBroadcastRadioFactory extends @1.1::IBroadcastRadioFactory {
+};
diff --git a/broadcastradio/1.2/ITuner.hal b/broadcastradio/1.2/ITuner.hal
new file mode 100644
index 0000000..ba97ea0
--- /dev/null
+++ b/broadcastradio/1.2/ITuner.hal
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio@1.2;
+
+import @1.1::ITuner;
+
+interface ITuner extends @1.1::ITuner {
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Framework does not make any assumptions on the keys or values, other than
+     * ones stated in VendorKeyValue documentation (a requirement of key
+     * prefixes).
+     *
+     * For each pair in the result vector, the key must be one of the keys
+     * contained in the input (possibly with wildcards expanded), and the value
+     * must be a vendor-specific result status (i.e. the string "OK" or an error
+     * code). The implementation may choose to return an empty vector, or only
+     * return a status for a subset of the provided inputs, at its discretion.
+     *
+     * Application and HAL must not use keys with unknown prefix. In particular,
+     * it must not place a key-value pair in results vector for unknown key from
+     * parameters vector - instead, an unknown key should simply be ignored.
+     * In other words, results vector may contain a subset of parameter keys
+     * (however, the framework doesn't enforce a strict subset - the only
+     * formal requirement is vendor domain prefix for keys).
+     *
+     * @param parameters Vendor-specific key-value pairs.
+     * @return results Operation completion status for parameters being set.
+     */
+    setParameters(vec<VendorKeyValue> parameters)
+            generates (vec<VendorKeyValue> results);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Framework does not cache set/get requests, so it's allowed for
+     * getParameter to return a different value than previous setParameter call.
+     *
+     * The syntax and semantics of keys are up to the vendor (as long as prefix
+     * rules are obeyed). For instance, vendors may include some form of
+     * wildcard support. In such case, result vector may be of different size
+     * than requested keys vector. However, wildcards are not recognized by
+     * framework and they are passed as-is to the HAL implementation.
+     *
+     * Unknown keys must be ignored and not placed into results vector.
+     *
+     * @param keys Parameter keys to fetch.
+     * @return parameters Vendor-specific key-value pairs.
+     */
+    getParameters(vec<string> keys) generates (vec<VendorKeyValue> parameters);
+};
diff --git a/broadcastradio/1.2/ITunerCallback.hal b/broadcastradio/1.2/ITunerCallback.hal
new file mode 100644
index 0000000..4e3d0a5
--- /dev/null
+++ b/broadcastradio/1.2/ITunerCallback.hal
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio@1.2;
+
+import @1.1::ITunerCallback;
+
+interface ITunerCallback extends @1.1::ITunerCallback {
+    /**
+     * Generic callback for passing updates to vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * It's up to the HAL implementation if and how to implement this callback,
+     * as long as it obeys the prefix rule. In particular, only selected keys
+     * may be notified this way. However, setParameters must not trigger
+     * this callback, while an internal event can change parameters
+     * asynchronously.
+     *
+     * @param parameters Vendor-specific key-value pairs.
+     */
+    oneway parametersUpdated(vec<VendorKeyValue> parameters);
+};
diff --git a/broadcastradio/1.2/default/Android.bp b/broadcastradio/1.2/default/Android.bp
new file mode 100644
index 0000000..bd4be77
--- /dev/null
+++ b/broadcastradio/1.2/default/Android.bp
@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+    name: "android.hardware.broadcastradio@1.2-service",
+    init_rc: ["android.hardware.broadcastradio@1.2-service.rc"],
+    vendor: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "BroadcastRadio.cpp",
+        "BroadcastRadioFactory.cpp",
+        "Tuner.cpp",
+        "VirtualProgram.cpp",
+        "VirtualRadio.cpp",
+        "service.cpp"
+    ],
+    static_libs: [
+        "android.hardware.broadcastradio@common-utils-1x-lib",
+        "android.hardware.broadcastradio@common-utils-lib",
+    ],
+    shared_libs: [
+        "android.hardware.broadcastradio@1.0",
+        "android.hardware.broadcastradio@1.1",
+        "android.hardware.broadcastradio@1.2",
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/broadcastradio/1.2/default/BroadcastRadio.cpp b/broadcastradio/1.2/default/BroadcastRadio.cpp
new file mode 100644
index 0000000..74f6589
--- /dev/null
+++ b/broadcastradio/1.2/default/BroadcastRadio.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BroadcastRadioDefault.module"
+#define LOG_NDEBUG 0
+
+#include "BroadcastRadio.h"
+
+#include <log/log.h>
+
+#include "resources.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+
+using V1_0::Band;
+using V1_0::BandConfig;
+using V1_0::Class;
+using V1_0::Deemphasis;
+using V1_0::Rds;
+using V1_1::IdentifierType;
+using V1_1::ProgramSelector;
+using V1_1::ProgramType;
+using V1_1::Properties;
+using V1_1::VendorKeyValue;
+
+using std::lock_guard;
+using std::map;
+using std::mutex;
+using std::vector;
+
+// clang-format off
+static const map<Class, ModuleConfig> gModuleConfigs{
+    {Class::AM_FM, ModuleConfig({
+        "Digital radio mock",
+        {  // amFmBands
+            AmFmBandConfig({
+                Band::AM,
+                153,         // lowerLimit
+                26100,       // upperLimit
+                {5, 9, 10},  // spacings
+            }),
+            AmFmBandConfig({
+                Band::FM,
+                65800,           // lowerLimit
+                108000,          // upperLimit
+                {10, 100, 200},  // spacings
+            }),
+            AmFmBandConfig({
+                Band::AM_HD,
+                153,         // lowerLimit
+                26100,       // upperLimit
+                {5, 9, 10},  // spacings
+            }),
+            AmFmBandConfig({
+                Band::FM_HD,
+                87700,   // lowerLimit
+                107900,  // upperLimit
+                {200},   // spacings
+            }),
+        },
+    })},
+
+    {Class::SAT, ModuleConfig({
+        "Satellite radio mock",
+        {},  // amFmBands
+    })},
+};
+// clang-format on
+
+BroadcastRadio::BroadcastRadio(Class classId)
+    : mClassId(classId), mConfig(gModuleConfigs.at(classId)) {}
+
+bool BroadcastRadio::isSupported(Class classId) {
+    return gModuleConfigs.find(classId) != gModuleConfigs.end();
+}
+
+Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    return getProperties_1_1(
+        [&](const Properties& properties) { _hidl_cb(Result::OK, properties.base); });
+}
+
+Return<void> BroadcastRadio::getProperties_1_1(getProperties_1_1_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    Properties prop11 = {};
+    auto& prop10 = prop11.base;
+
+    prop10.classId = mClassId;
+    prop10.implementor = "Google";
+    prop10.product = mConfig.productName;
+    prop10.numTuners = 1;
+    prop10.numAudioSources = 1;
+    prop10.supportsCapture = false;
+    prop11.supportsBackgroundScanning = true;
+    prop11.supportedProgramTypes = hidl_vec<uint32_t>({
+        static_cast<uint32_t>(ProgramType::AM), static_cast<uint32_t>(ProgramType::FM),
+        static_cast<uint32_t>(ProgramType::AM_HD), static_cast<uint32_t>(ProgramType::FM_HD),
+    });
+    prop11.supportedIdentifierTypes = hidl_vec<uint32_t>({
+        static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY),
+        static_cast<uint32_t>(IdentifierType::RDS_PI),
+        static_cast<uint32_t>(IdentifierType::HD_STATION_ID_EXT),
+        static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL),
+    });
+    prop11.vendorInfo = hidl_vec<VendorKeyValue>({
+        {"com.google.dummy", "dummy"},
+    });
+
+    prop10.bands.resize(mConfig.amFmBands.size());
+    for (size_t i = 0; i < mConfig.amFmBands.size(); i++) {
+        auto& src = mConfig.amFmBands[i];
+        auto& dst = prop10.bands[i];
+
+        dst.type = src.type;
+        dst.antennaConnected = true;
+        dst.lowerLimit = src.lowerLimit;
+        dst.upperLimit = src.upperLimit;
+        dst.spacings = src.spacings;
+
+        if (utils::isAm(src.type)) {
+            dst.ext.am.stereo = true;
+        } else if (utils::isFm(src.type)) {
+            dst.ext.fm.deemphasis = static_cast<Deemphasis>(Deemphasis::D50 | Deemphasis::D75);
+            dst.ext.fm.stereo = true;
+            dst.ext.fm.rds = static_cast<Rds>(Rds::WORLD | Rds::US);
+            dst.ext.fm.ta = true;
+            dst.ext.fm.af = true;
+            dst.ext.fm.ea = true;
+        }
+    }
+
+    _hidl_cb(prop11);
+    return Void();
+}
+
+Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio __unused,
+                                       const sp<V1_0::ITunerCallback>& callback,
+                                       openTuner_cb _hidl_cb) {
+    ALOGV("%s(%s)", __func__, toString(config.type).c_str());
+    lock_guard<mutex> lk(mMut);
+
+    auto oldTuner = mTuner.promote();
+    if (oldTuner != nullptr) {
+        ALOGI("Force-closing previously opened tuner");
+        oldTuner->forceClose();
+        mTuner = nullptr;
+    }
+
+    sp<Tuner> newTuner = new Tuner(mClassId, callback);
+    mTuner = newTuner;
+    if (mClassId == Class::AM_FM) {
+        auto ret = newTuner->setConfiguration(config);
+        if (ret != Result::OK) {
+            _hidl_cb(Result::INVALID_ARGUMENTS, {});
+            return Void();
+        }
+    }
+
+    _hidl_cb(Result::OK, newTuner);
+    return Void();
+}
+
+Return<void> BroadcastRadio::getImage(int32_t id, getImage_cb _hidl_cb) {
+    ALOGV("%s(%x)", __func__, id);
+
+    if (id == resources::demoPngId) {
+        _hidl_cb(std::vector<uint8_t>(resources::demoPng, std::end(resources::demoPng)));
+        return {};
+    }
+
+    ALOGI("Image %x doesn't exists", id);
+    _hidl_cb({});
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.2/default/BroadcastRadio.h b/broadcastradio/1.2/default/BroadcastRadio.h
new file mode 100644
index 0000000..94d62b9
--- /dev/null
+++ b/broadcastradio/1.2/default/BroadcastRadio.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_2_BROADCASTRADIO_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_2_BROADCASTRADIO_H
+
+#include "Tuner.h"
+
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/1.2/types.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+
+struct AmFmBandConfig {
+    V1_0::Band type;
+    uint32_t lowerLimit;  // kHz
+    uint32_t upperLimit;  // kHz
+    std::vector<uint32_t> spacings;  // kHz
+};
+
+struct ModuleConfig {
+    std::string productName;
+    std::vector<AmFmBandConfig> amFmBands;
+};
+
+struct BroadcastRadio : public V1_1::IBroadcastRadio {
+    /**
+     * Constructs new broadcast radio module.
+     *
+     * Before calling a constructor with a given classId, it must be checked with isSupported
+     * method first. Otherwise it results in undefined behaviour.
+     *
+     * @param classId type of a radio.
+     */
+    BroadcastRadio(V1_0::Class classId);
+
+    /**
+     * Checks, if a given radio type is supported.
+     *
+     * @param classId type of a radio.
+     */
+    static bool isSupported(V1_0::Class classId);
+
+    // V1_1::IBroadcastRadio methods
+    Return<void> getProperties(getProperties_cb _hidl_cb) override;
+    Return<void> getProperties_1_1(getProperties_1_1_cb _hidl_cb) override;
+    Return<void> openTuner(const V1_0::BandConfig& config, bool audio,
+                           const sp<V1_0::ITunerCallback>& callback,
+                           openTuner_cb _hidl_cb) override;
+    Return<void> getImage(int32_t id, getImage_cb _hidl_cb);
+
+   private:
+    std::mutex mMut;
+    V1_0::Class mClassId;
+    ModuleConfig mConfig;
+    wp<Tuner> mTuner;
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_2_BROADCASTRADIO_H
diff --git a/broadcastradio/1.2/default/BroadcastRadioFactory.cpp b/broadcastradio/1.2/default/BroadcastRadioFactory.cpp
new file mode 100644
index 0000000..8f17aff
--- /dev/null
+++ b/broadcastradio/1.2/default/BroadcastRadioFactory.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BroadcastRadioDefault.factory"
+#define LOG_NDEBUG 0
+
+#include "BroadcastRadioFactory.h"
+
+#include "BroadcastRadio.h"
+
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+
+using V1_0::Class;
+
+using std::vector;
+
+static const vector<Class> gAllClasses = {
+    Class::AM_FM, Class::SAT, Class::DT,
+};
+
+BroadcastRadioFactory::BroadcastRadioFactory() {
+    for (auto&& classId : gAllClasses) {
+        if (!BroadcastRadio::isSupported(classId)) continue;
+        mRadioModules[classId] = new BroadcastRadio(classId);
+    }
+}
+
+Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) {
+    ALOGV("%s(%s)", __func__, toString(classId).c_str());
+
+    auto moduleIt = mRadioModules.find(classId);
+    if (moduleIt == mRadioModules.end()) {
+        _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
+    } else {
+        _hidl_cb(Result::OK, moduleIt->second);
+    }
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.2/default/BroadcastRadioFactory.h b/broadcastradio/1.2/default/BroadcastRadioFactory.h
new file mode 100644
index 0000000..c365ae0
--- /dev/null
+++ b/broadcastradio/1.2/default/BroadcastRadioFactory.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_2_BROADCASTRADIOFACTORY_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_2_BROADCASTRADIOFACTORY_H
+
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.2/types.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+
+struct BroadcastRadioFactory : public IBroadcastRadioFactory {
+    BroadcastRadioFactory();
+
+    // V1_0::IBroadcastRadioFactory methods
+    Return<void> connectModule(V1_0::Class classId, connectModule_cb _hidl_cb) override;
+
+   private:
+    std::map<V1_0::Class, sp<V1_1::IBroadcastRadio>> mRadioModules;
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_2_BROADCASTRADIOFACTORY_H
diff --git a/broadcastradio/1.2/default/OWNERS b/broadcastradio/1.2/default/OWNERS
new file mode 100644
index 0000000..136b607
--- /dev/null
+++ b/broadcastradio/1.2/default/OWNERS
@@ -0,0 +1,3 @@
+# Automotive team
+egranata@google.com
+twasilczyk@google.com
diff --git a/broadcastradio/1.2/default/Tuner.cpp b/broadcastradio/1.2/default/Tuner.cpp
new file mode 100644
index 0000000..e95a132
--- /dev/null
+++ b/broadcastradio/1.2/default/Tuner.cpp
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BroadcastRadioDefault.tuner"
+#define LOG_NDEBUG 0
+
+#include "BroadcastRadio.h"
+#include "Tuner.h"
+
+#include <broadcastradio-utils-1x/Utils.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+
+using namespace std::chrono_literals;
+
+using V1_0::Band;
+using V1_0::BandConfig;
+using V1_0::Class;
+using V1_0::Direction;
+using V1_1::ProgramInfo;
+using V1_1::ProgramInfoFlags;
+using V1_1::ProgramListResult;
+using V1_1::ProgramSelector;
+using V1_1::ProgramType;
+using V1_1::VendorKeyValue;
+using V1_2::IdentifierType;
+using utils::HalRevision;
+
+using std::chrono::milliseconds;
+using std::lock_guard;
+using std::move;
+using std::mutex;
+using std::sort;
+using std::vector;
+
+const struct {
+    milliseconds config = 50ms;
+    milliseconds scan = 200ms;
+    milliseconds step = 100ms;
+    milliseconds tune = 150ms;
+} gDefaultDelay;
+
+Tuner::Tuner(V1_0::Class classId, const sp<V1_0::ITunerCallback>& callback)
+    : mClassId(classId),
+      mCallback(callback),
+      mCallback1_1(V1_1::ITunerCallback::castFrom(callback).withDefault(nullptr)),
+      mCallback1_2(V1_2::ITunerCallback::castFrom(callback).withDefault(nullptr)),
+      mVirtualRadio(getRadio(classId)),
+      mIsAnalogForced(false) {}
+
+void Tuner::forceClose() {
+    lock_guard<mutex> lk(mMut);
+    mIsClosed = true;
+    mThread.cancelAll();
+}
+
+Return<Result> Tuner::setConfiguration(const BandConfig& config) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::NOT_INITIALIZED;
+    if (mClassId != Class::AM_FM) {
+        ALOGE("Can't set AM/FM configuration on SAT/DT radio tuner");
+        return Result::INVALID_STATE;
+    }
+
+    if (config.lowerLimit >= config.upperLimit) return Result::INVALID_ARGUMENTS;
+
+    auto task = [this, config]() {
+        ALOGI("Setting AM/FM config");
+        lock_guard<mutex> lk(mMut);
+
+        mAmfmConfig = move(config);
+        mAmfmConfig.antennaConnected = true;
+        mCurrentProgram = utils::make_selector(mAmfmConfig.type, mAmfmConfig.lowerLimit);
+
+        if (utils::isFm(mAmfmConfig.type)) {
+            mVirtualRadio = std::ref(getFmRadio());
+        } else {
+            mVirtualRadio = std::ref(getAmRadio());
+        }
+
+        mIsAmfmConfigSet = true;
+        mCallback->configChange(Result::OK, mAmfmConfig);
+    };
+    mThread.schedule(task, gDefaultDelay.config);
+
+    return Result::OK;
+}
+
+Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+
+    if (!mIsClosed && mIsAmfmConfigSet) {
+        _hidl_cb(Result::OK, mAmfmConfig);
+    } else {
+        _hidl_cb(Result::NOT_INITIALIZED, {});
+    }
+    return {};
+}
+
+// makes ProgramInfo that points to no program
+static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) {
+    ProgramInfo info11 = {};
+    auto& info10 = info11.base;
+
+    utils::getLegacyChannel(selector, &info10.channel, &info10.subChannel);
+    info11.selector = selector;
+    info11.flags |= ProgramInfoFlags::MUTED;
+
+    return info11;
+}
+
+HalRevision Tuner::getHalRev() const {
+    if (mCallback1_2 != nullptr) {
+        return HalRevision::V1_2;
+    } else if (mCallback1_1 != nullptr) {
+        return HalRevision::V1_1;
+    } else {
+        return HalRevision::V1_0;
+    }
+}
+
+void Tuner::tuneInternalLocked(const ProgramSelector& sel) {
+    VirtualProgram virtualProgram;
+    if (mVirtualRadio.get().getProgram(sel, virtualProgram)) {
+        mCurrentProgram = virtualProgram.selector;
+        mCurrentProgramInfo = virtualProgram.getProgramInfo(getHalRev());
+    } else {
+        mCurrentProgram = sel;
+        mCurrentProgramInfo = makeDummyProgramInfo(sel);
+    }
+    mIsTuneCompleted = true;
+
+    if (mCallback1_1 == nullptr) {
+        mCallback->tuneComplete(Result::OK, mCurrentProgramInfo.base);
+    } else {
+        mCallback1_1->tuneComplete_1_1(Result::OK, mCurrentProgramInfo.selector);
+        mCallback1_1->currentProgramInfoChanged(mCurrentProgramInfo);
+    }
+}
+
+Return<Result> Tuner::scan(Direction direction, bool skipSubChannel __unused) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::NOT_INITIALIZED;
+
+    auto list = mVirtualRadio.get().getProgramList();
+
+    if (list.empty()) {
+        mIsTuneCompleted = false;
+        auto task = [this, direction]() {
+            ALOGI("Performing failed scan %s", toString(direction).c_str());
+
+            if (mCallback1_1 == nullptr) {
+                mCallback->tuneComplete(Result::TIMEOUT, {});
+            } else {
+                mCallback1_1->tuneComplete_1_1(Result::TIMEOUT, {});
+            }
+        };
+        mThread.schedule(task, gDefaultDelay.scan);
+
+        return Result::OK;
+    }
+
+    // Not optimal (O(sort) instead of O(n)), but not a big deal here;
+    // also, it's likely that list is already sorted (so O(n) anyway).
+    sort(list.begin(), list.end());
+    auto current = mCurrentProgram;
+    auto found = lower_bound(list.begin(), list.end(), VirtualProgram({current}));
+    if (direction == Direction::UP) {
+        if (found < list.end() - 1) {
+            if (utils::tunesTo(current, found->selector)) found++;
+        } else {
+            found = list.begin();
+        }
+    } else {
+        if (found > list.begin() && found != list.end()) {
+            found--;
+        } else {
+            found = list.end() - 1;
+        }
+    }
+    auto tuneTo = found->selector;
+
+    mIsTuneCompleted = false;
+    auto task = [this, tuneTo, direction]() {
+        ALOGI("Performing scan %s", toString(direction).c_str());
+
+        lock_guard<mutex> lk(mMut);
+        tuneInternalLocked(tuneTo);
+    };
+    mThread.schedule(task, gDefaultDelay.scan);
+
+    return Result::OK;
+}
+
+Return<Result> Tuner::step(Direction direction, bool skipSubChannel) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::NOT_INITIALIZED;
+
+    ALOGW_IF(!skipSubChannel, "can't step to next frequency without ignoring subChannel");
+
+    if (!utils::isAmFm(utils::getType(mCurrentProgram))) {
+        ALOGE("Can't step in anything else than AM/FM");
+        return Result::NOT_INITIALIZED;
+    }
+
+    if (!mIsAmfmConfigSet) {
+        ALOGW("AM/FM config not set");
+        return Result::INVALID_STATE;
+    }
+    mIsTuneCompleted = false;
+
+    auto task = [this, direction]() {
+        ALOGI("Performing step %s", toString(direction).c_str());
+
+        lock_guard<mutex> lk(mMut);
+
+        auto current = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY, 0);
+
+        if (direction == Direction::UP) {
+            current += mAmfmConfig.spacings[0];
+        } else {
+            current -= mAmfmConfig.spacings[0];
+        }
+
+        if (current > mAmfmConfig.upperLimit) current = mAmfmConfig.lowerLimit;
+        if (current < mAmfmConfig.lowerLimit) current = mAmfmConfig.upperLimit;
+
+        tuneInternalLocked(utils::make_selector(mAmfmConfig.type, current));
+    };
+    mThread.schedule(task, gDefaultDelay.step);
+
+    return Result::OK;
+}
+
+Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) {
+    ALOGV("%s(%d, %d)", __func__, channel, subChannel);
+    Band band;
+    {
+        lock_guard<mutex> lk(mMut);
+        band = mAmfmConfig.type;
+    }
+    return tuneByProgramSelector(utils::make_selector(band, channel, subChannel));
+}
+
+Return<Result> Tuner::tuneByProgramSelector(const ProgramSelector& sel) {
+    ALOGV("%s(%s)", __func__, toString(sel).c_str());
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::NOT_INITIALIZED;
+
+    // checking if ProgramSelector is valid
+    auto programType = utils::getType(sel);
+    if (utils::isAmFm(programType)) {
+        if (!mIsAmfmConfigSet) {
+            ALOGW("AM/FM config not set");
+            return Result::INVALID_STATE;
+        }
+
+        auto freq = utils::getId(sel, IdentifierType::AMFM_FREQUENCY);
+        if (freq < mAmfmConfig.lowerLimit || freq > mAmfmConfig.upperLimit) {
+            return Result::INVALID_ARGUMENTS;
+        }
+    } else if (programType == ProgramType::DAB) {
+        if (!utils::hasId(sel, IdentifierType::DAB_SID_EXT)) return Result::INVALID_ARGUMENTS;
+    } else if (programType == ProgramType::DRMO) {
+        if (!utils::hasId(sel, IdentifierType::DRMO_SERVICE_ID)) return Result::INVALID_ARGUMENTS;
+    } else if (programType == ProgramType::SXM) {
+        if (!utils::hasId(sel, IdentifierType::SXM_SERVICE_ID)) return Result::INVALID_ARGUMENTS;
+    } else {
+        return Result::INVALID_ARGUMENTS;
+    }
+
+    mIsTuneCompleted = false;
+    auto task = [this, sel]() {
+        lock_guard<mutex> lk(mMut);
+        tuneInternalLocked(sel);
+    };
+    mThread.schedule(task, gDefaultDelay.tune);
+
+    return Result::OK;
+}
+
+Return<Result> Tuner::cancel() {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::NOT_INITIALIZED;
+
+    mThread.cancelAll();
+    return Result::OK;
+}
+
+Return<Result> Tuner::cancelAnnouncement() {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::NOT_INITIALIZED;
+
+    return Result::OK;
+}
+
+Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    return getProgramInformation_1_1(
+        [&](Result result, const ProgramInfo& info) { _hidl_cb(result, info.base); });
+}
+
+Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+
+    if (mIsClosed) {
+        _hidl_cb(Result::NOT_INITIALIZED, {});
+    } else if (mIsTuneCompleted) {
+        _hidl_cb(Result::OK, mCurrentProgramInfo);
+    } else {
+        _hidl_cb(Result::NOT_INITIALIZED, makeDummyProgramInfo(mCurrentProgram));
+    }
+    return {};
+}
+
+Return<ProgramListResult> Tuner::startBackgroundScan() {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return ProgramListResult::NOT_INITIALIZED;
+
+    if (mCallback1_1 != nullptr) {
+        mCallback1_1->backgroundScanComplete(ProgramListResult::OK);
+    }
+
+    return ProgramListResult::OK;
+}
+
+Return<void> Tuner::getProgramList(const hidl_vec<VendorKeyValue>& vendorFilter,
+                                   getProgramList_cb _hidl_cb) {
+    ALOGV("%s(%s)", __func__, toString(vendorFilter).substr(0, 100).c_str());
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) {
+        _hidl_cb(ProgramListResult::NOT_INITIALIZED, {});
+        return {};
+    }
+
+    auto list = mVirtualRadio.get().getProgramList();
+    ALOGD("returning a list of %zu programs", list.size());
+    _hidl_cb(ProgramListResult::OK, getProgramInfoVector(list, getHalRev()));
+    return {};
+}
+
+Return<Result> Tuner::setAnalogForced(bool isForced) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::NOT_INITIALIZED;
+
+    mIsAnalogForced = isForced;
+    return Result::OK;
+}
+
+Return<void> Tuner::isAnalogForced(isAnalogForced_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+
+    if (mIsClosed) {
+        _hidl_cb(Result::NOT_INITIALIZED, false);
+    } else {
+        _hidl_cb(Result::OK, mIsAnalogForced);
+    }
+    return {};
+}
+
+Return<void> Tuner::setParameters(const hidl_vec<VendorKeyValue>& /* parameters */,
+        setParameters_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+
+    _hidl_cb({});
+    return {};
+}
+
+Return<void> Tuner::getParameters(const hidl_vec<hidl_string>& /* keys */,
+        getParameters_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+
+    _hidl_cb({});
+    return {};
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.2/default/Tuner.h b/broadcastradio/1.2/default/Tuner.h
new file mode 100644
index 0000000..7e68354
--- /dev/null
+++ b/broadcastradio/1.2/default/Tuner.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_2_TUNER_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_2_TUNER_H
+
+#include "VirtualRadio.h"
+
+#include <android/hardware/broadcastradio/1.2/ITuner.h>
+#include <android/hardware/broadcastradio/1.2/ITunerCallback.h>
+#include <broadcastradio-utils/WorkerThread.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+
+struct Tuner : public ITuner {
+    Tuner(V1_0::Class classId, const sp<V1_0::ITunerCallback>& callback);
+
+    void forceClose();
+
+    // V1_2::ITuner methods
+    virtual Return<Result> setConfiguration(const V1_0::BandConfig& config) override;
+    virtual Return<void> getConfiguration(getConfiguration_cb _hidl_cb) override;
+    virtual Return<Result> scan(V1_0::Direction direction, bool skipSubChannel) override;
+    virtual Return<Result> step(V1_0::Direction direction, bool skipSubChannel) override;
+    virtual Return<Result> tune(uint32_t channel, uint32_t subChannel) override;
+    virtual Return<Result> tuneByProgramSelector(const V1_1::ProgramSelector& program) override;
+    virtual Return<Result> cancel() override;
+    virtual Return<Result> cancelAnnouncement() override;
+    virtual Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override;
+    virtual Return<void> getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) override;
+    virtual Return<V1_1::ProgramListResult> startBackgroundScan() override;
+    virtual Return<void> getProgramList(const hidl_vec<V1_1::VendorKeyValue>& filter,
+                                        getProgramList_cb _hidl_cb) override;
+    virtual Return<Result> setAnalogForced(bool isForced) override;
+    virtual Return<void> isAnalogForced(isAnalogForced_cb _hidl_cb) override;
+    virtual Return<void> setParameters(const hidl_vec<V1_1::VendorKeyValue>& parameters,
+                                       setParameters_cb _hidl_cb) override;
+    virtual Return<void> getParameters(const hidl_vec<hidl_string>& keys,
+                                       getParameters_cb _hidl_cb) override;
+
+   private:
+    std::mutex mMut;
+    WorkerThread mThread;
+    bool mIsClosed = false;
+
+    V1_0::Class mClassId;
+    const sp<V1_0::ITunerCallback> mCallback;
+    const sp<V1_1::ITunerCallback> mCallback1_1;
+    const sp<V1_2::ITunerCallback> mCallback1_2;
+
+    std::reference_wrapper<VirtualRadio> mVirtualRadio;
+    bool mIsAmfmConfigSet = false;
+    V1_0::BandConfig mAmfmConfig;
+    bool mIsTuneCompleted = false;
+    V1_1::ProgramSelector mCurrentProgram = {};
+    V1_1::ProgramInfo mCurrentProgramInfo = {};
+    std::atomic<bool> mIsAnalogForced;
+
+    utils::HalRevision getHalRev() const;
+    void tuneInternalLocked(const V1_1::ProgramSelector& sel);
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_2_TUNER_H
diff --git a/broadcastradio/1.2/default/VirtualProgram.cpp b/broadcastradio/1.2/default/VirtualProgram.cpp
new file mode 100644
index 0000000..3594f64
--- /dev/null
+++ b/broadcastradio/1.2/default/VirtualProgram.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "VirtualProgram.h"
+
+#include <broadcastradio-utils-1x/Utils.h>
+
+#include "resources.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+
+using std::vector;
+
+using V1_0::MetaData;
+using V1_0::MetadataKey;
+using V1_0::MetadataType;
+using V1_1::ProgramInfo;
+using V1_1::VendorKeyValue;
+using V1_2::IdentifierType;
+using utils::HalRevision;
+
+static MetaData createDemoBitmap(MetadataKey key, HalRevision halRev) {
+    MetaData bmp = {MetadataType::INT, key, resources::demoPngId, {}, {}, {}};
+    if (halRev < HalRevision::V1_1) {
+        bmp.type = MetadataType::RAW;
+        bmp.intValue = 0;
+        bmp.rawValue = hidl_vec<uint8_t>(resources::demoPng, std::end(resources::demoPng));
+    }
+    return bmp;
+}
+
+ProgramInfo VirtualProgram::getProgramInfo(HalRevision halRev) const {
+    ProgramInfo info11 = {};
+    auto& info10 = info11.base;
+
+    utils::getLegacyChannel(selector, &info10.channel, &info10.subChannel);
+    info11.selector = selector;
+    info10.tuned = true;
+    info10.stereo = true;
+    info10.digital = utils::isDigital(selector);
+    info10.signalStrength = info10.digital ? 100 : 80;
+
+    info10.metadata = hidl_vec<MetaData>({
+        {MetadataType::TEXT, MetadataKey::RDS_PS, {}, {}, programName, {}},
+        {MetadataType::TEXT, MetadataKey::TITLE, {}, {}, songTitle, {}},
+        {MetadataType::TEXT, MetadataKey::ARTIST, {}, {}, songArtist, {}},
+        createDemoBitmap(MetadataKey::ICON, halRev),
+        createDemoBitmap(MetadataKey::ART, halRev),
+    });
+
+    info11.vendorInfo = hidl_vec<VendorKeyValue>({
+        {"com.google.dummy", "dummy"},
+        {"com.google.dummy.VirtualProgram", std::to_string(reinterpret_cast<uintptr_t>(this))},
+    });
+
+    return info11;
+}
+
+// Defining order on virtual programs, how they appear on band.
+// It's mostly for default implementation purposes, may not be complete or correct.
+bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs) {
+    auto& l = lhs.selector;
+    auto& r = rhs.selector;
+
+    // Two programs with the same primaryId is considered the same.
+    if (l.programType != r.programType) return l.programType < r.programType;
+    if (l.primaryId.type != r.primaryId.type) return l.primaryId.type < r.primaryId.type;
+    if (l.primaryId.value != r.primaryId.value) return l.primaryId.value < r.primaryId.value;
+
+    return false;
+}
+
+vector<ProgramInfo> getProgramInfoVector(const vector<VirtualProgram>& vec, HalRevision halRev) {
+    vector<ProgramInfo> out;
+    out.reserve(vec.size());
+    for (auto&& program : vec) {
+        out.push_back(program.getProgramInfo(halRev));
+    }
+    return out;
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.2/default/VirtualProgram.h b/broadcastradio/1.2/default/VirtualProgram.h
new file mode 100644
index 0000000..c0b20f0
--- /dev/null
+++ b/broadcastradio/1.2/default/VirtualProgram.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_2_VIRTUALPROGRAM_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_2_VIRTUALPROGRAM_H
+
+#include <android/hardware/broadcastradio/1.2/types.h>
+#include <broadcastradio-utils-1x/Utils.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+
+/**
+ * A radio program mock.
+ *
+ * This represents broadcast waves flying over the air,
+ * not an entry for a captured station in the radio tuner memory.
+ */
+struct VirtualProgram {
+    V1_1::ProgramSelector selector;
+
+    std::string programName = "";
+    std::string songArtist = "";
+    std::string songTitle = "";
+
+    V1_1::ProgramInfo getProgramInfo(utils::HalRevision halRev) const;
+
+    friend bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs);
+};
+
+std::vector<V1_1::ProgramInfo> getProgramInfoVector(const std::vector<VirtualProgram>& vec,
+                                                    utils::HalRevision halRev);
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_2_VIRTUALPROGRAM_H
diff --git a/broadcastradio/1.2/default/VirtualRadio.cpp b/broadcastradio/1.2/default/VirtualRadio.cpp
new file mode 100644
index 0000000..8988080
--- /dev/null
+++ b/broadcastradio/1.2/default/VirtualRadio.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BroadcastRadioDefault.VirtualRadio"
+//#define LOG_NDEBUG 0
+
+#include "VirtualRadio.h"
+
+#include <broadcastradio-utils-1x/Utils.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+
+using V1_0::Band;
+using V1_0::Class;
+using V1_1::ProgramSelector;
+
+using std::lock_guard;
+using std::move;
+using std::mutex;
+using std::vector;
+
+using utils::make_selector;
+
+static const vector<VirtualProgram> gInitialFmPrograms{
+    {make_selector(Band::FM, 94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
+    {make_selector(Band::FM, 96500), "KOIT", "Celine Dion", "All By Myself"},
+    {make_selector(Band::FM, 97300), "Alice@97.3", "Drops of Jupiter", "Train"},
+    {make_selector(Band::FM, 99700), "99.7 Now!", "The Chainsmokers", "Closer"},
+    {make_selector(Band::FM, 101300), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"},
+    {make_selector(Band::FM, 103700), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"},
+    {make_selector(Band::FM, 106100), "106 KMEL", "Drake", "Marvins Room"},
+};
+
+static VirtualRadio gEmptyRadio({});
+static VirtualRadio gFmRadio(gInitialFmPrograms);
+
+VirtualRadio::VirtualRadio(const vector<VirtualProgram> initialList) : mPrograms(initialList) {}
+
+vector<VirtualProgram> VirtualRadio::getProgramList() {
+    lock_guard<mutex> lk(mMut);
+    return mPrograms;
+}
+
+bool VirtualRadio::getProgram(const ProgramSelector& selector, VirtualProgram& programOut) {
+    lock_guard<mutex> lk(mMut);
+    for (auto&& program : mPrograms) {
+        if (utils::tunesTo(selector, program.selector)) {
+            programOut = program;
+            return true;
+        }
+    }
+    return false;
+}
+
+VirtualRadio& getRadio(V1_0::Class classId) {
+    switch (classId) {
+        case Class::AM_FM:
+            return getFmRadio();
+        case Class::SAT:
+            return getSatRadio();
+        case Class::DT:
+            return getDigitalRadio();
+        default:
+            ALOGE("Invalid class ID");
+            return gEmptyRadio;
+    }
+}
+
+VirtualRadio& getAmRadio() {
+    return gEmptyRadio;
+}
+
+VirtualRadio& getFmRadio() {
+    return gFmRadio;
+}
+
+VirtualRadio& getSatRadio() {
+    return gEmptyRadio;
+}
+
+VirtualRadio& getDigitalRadio() {
+    return gEmptyRadio;
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.2/default/VirtualRadio.h b/broadcastradio/1.2/default/VirtualRadio.h
new file mode 100644
index 0000000..8cfaefe
--- /dev/null
+++ b/broadcastradio/1.2/default/VirtualRadio.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_2_VIRTUALRADIO_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_2_VIRTUALRADIO_H
+
+#include "VirtualProgram.h"
+
+#include <mutex>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+
+/**
+ * A radio frequency space mock.
+ *
+ * This represents all broadcast waves in the air for a given radio technology,
+ * not a captured station list in the radio tuner memory.
+ *
+ * It's meant to abstract out radio content from default tuner implementation.
+ */
+class VirtualRadio {
+   public:
+    VirtualRadio(const std::vector<VirtualProgram> initialList);
+
+    std::vector<VirtualProgram> getProgramList();
+    bool getProgram(const V1_1::ProgramSelector& selector, VirtualProgram& program);
+
+   private:
+    std::mutex mMut;
+    std::vector<VirtualProgram> mPrograms;
+};
+
+/**
+ * Get virtual radio space for a given radio class.
+ *
+ * As a space, each virtual radio always exists. For example, DAB frequencies
+ * exists in US, but contains no programs.
+ *
+ * The lifetime of the virtual radio space is virtually infinite, but for the
+ * needs of default implementation, it's bound with the lifetime of default
+ * implementation process.
+ *
+ * Internally, it's a static object, so trying to access the reference during
+ * default implementation library unloading may result in segmentation fault.
+ * It's unlikely for testing purposes.
+ *
+ * @param classId A class of radio technology.
+ * @return A reference to virtual radio space for a given technology.
+ */
+VirtualRadio& getRadio(V1_0::Class classId);
+
+VirtualRadio& getAmRadio();
+VirtualRadio& getFmRadio();
+VirtualRadio& getSatRadio();
+VirtualRadio& getDigitalRadio();
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_2_VIRTUALRADIO_H
diff --git a/broadcastradio/1.2/default/android.hardware.broadcastradio@1.2-service.rc b/broadcastradio/1.2/default/android.hardware.broadcastradio@1.2-service.rc
new file mode 100644
index 0000000..3741f21
--- /dev/null
+++ b/broadcastradio/1.2/default/android.hardware.broadcastradio@1.2-service.rc
@@ -0,0 +1,4 @@
+service broadcastradio-hal /vendor/bin/hw/android.hardware.broadcastradio@1.2-service
+    class hal
+    user audioserver
+    group audio
diff --git a/broadcastradio/1.2/default/resources.h b/broadcastradio/1.2/default/resources.h
new file mode 100644
index 0000000..b383c27
--- /dev/null
+++ b/broadcastradio/1.2/default/resources.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_2_RESOURCES_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_2_RESOURCES_H
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace implementation {
+namespace resources {
+
+constexpr int32_t demoPngId = 123456;
+constexpr uint8_t demoPng[] = {
+    0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44,
+    0x52, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x08, 0x02, 0x00, 0x00, 0x00, 0x25,
+    0x0b, 0xe6, 0x89, 0x00, 0x00, 0x00, 0x5d, 0x49, 0x44, 0x41, 0x54, 0x68, 0xde, 0xed, 0xd9,
+    0xc1, 0x09, 0x00, 0x30, 0x08, 0x04, 0xc1, 0x33, 0xfd, 0xf7, 0x6c, 0x6a, 0xc8, 0x23, 0x04,
+    0xc9, 0x6c, 0x01, 0xc2, 0x20, 0xbe, 0x4c, 0x86, 0x57, 0x49, 0xba, 0xfb, 0xd6, 0xf4, 0xba,
+    0x3e, 0x7f, 0x4d, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8f, 0x00, 0xbd, 0xce, 0x7f,
+    0xc0, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xb8, 0x0d, 0x32, 0xd4, 0x0c, 0x77, 0xbd,
+    0xfb, 0xc1, 0xce, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+
+}  // namespace resources
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_2_RESOURCES_H
diff --git a/broadcastradio/1.2/default/service.cpp b/broadcastradio/1.2/default/service.cpp
new file mode 100644
index 0000000..ea86fba
--- /dev/null
+++ b/broadcastradio/1.2/default/service.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BroadcastRadioDefault.service"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "BroadcastRadioFactory.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::broadcastradio::V1_2::implementation::BroadcastRadioFactory;
+
+int main(int /* argc */, char** /* argv */) {
+    configureRpcThreadpool(4, true);
+
+    BroadcastRadioFactory broadcastRadioFactory;
+    auto status = broadcastRadioFactory.registerAsService();
+    CHECK_EQ(status, android::OK) << "Failed to register Broadcast Radio HAL implementation";
+
+    joinRpcThreadpool();
+    return 1;  // joinRpcThreadpool shouldn't exit
+}
diff --git a/broadcastradio/1.2/types.hal b/broadcastradio/1.2/types.hal
new file mode 100644
index 0000000..7301e13
--- /dev/null
+++ b/broadcastradio/1.2/types.hal
@@ -0,0 +1,50 @@
+/**
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio@1.2;
+
+import @1.1::IdentifierType;
+import @1.1::Result;
+import @1.1::VendorKeyValue;
+
+typedef @1.1::Result Result;
+typedef @1.1::VendorKeyValue VendorKeyValue;
+
+enum IdentifierType : @1.1::IdentifierType {
+    /**
+     * 28bit compound primary identifier for DAB.
+     *
+     * Consists of (from the LSB):
+     * - 16bit: SId;
+     * - 8bit: ECC code;
+     * - 4bit: SCIdS (optional).
+     *
+     * SCIdS (Service Component Identifier within the Service) value
+     * of 0 represents the main service, while 1 and above represents
+     * secondary services.
+     *
+     * The remaining bits should be set to zeros when writing on the chip side
+     * and ignored when read.
+     *
+     * This identifier deprecates DAB_SIDECC and makes new primary identifier
+     * for DAB. If the hal implementation detects 1.2 client (by casting
+     * V1_0::ITunerCallback to V1_2::ITunerCallback), it must use DAB_SID_EXT
+     * as a primary identifier for DAB program type. If the hal client detects
+     * either 1.1 or 1.2 HAL, it must convert those identifiers to the
+     * correct version.
+     */
+    DAB_SID_EXT = SXM_CHANNEL + 1,
+};
diff --git a/broadcastradio/1.2/vts/OWNERS b/broadcastradio/1.2/vts/OWNERS
new file mode 100644
index 0000000..12adf57
--- /dev/null
+++ b/broadcastradio/1.2/vts/OWNERS
@@ -0,0 +1,7 @@
+# Automotive team
+egranata@google.com
+twasilczyk@google.com
+
+# VTS team
+yuexima@google.com
+yim@google.com
diff --git a/broadcastradio/1.2/vts/functional/Android.bp b/broadcastradio/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..fd1c254
--- /dev/null
+++ b/broadcastradio/1.2/vts/functional/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalBroadcastradioV1_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBroadcastradioV1_2TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.broadcastradio@1.0",
+        "android.hardware.broadcastradio@1.1",
+        "android.hardware.broadcastradio@1.2",
+        "android.hardware.broadcastradio@vts-utils-lib",
+        "libgmock",
+    ],
+}
diff --git a/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp b/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp
new file mode 100644
index 0000000..085206b
--- /dev/null
+++ b/broadcastradio/1.2/vts/functional/VtsHalBroadcastradioV1_2TargetTest.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "broadcastradio.vts"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.2/ITuner.h>
+#include <android/hardware/broadcastradio/1.2/ITunerCallback.h>
+#include <android/hardware/broadcastradio/1.2/types.h>
+#include <broadcastradio-vts-utils/call-barrier.h>
+#include <broadcastradio-vts-utils/mock-timeout.h>
+#include <broadcastradio-vts-utils/pointer-utils.h>
+#include <cutils/native_handle.h>
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/threads.h>
+
+#include <chrono>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_2 {
+namespace vts {
+
+using namespace std::chrono_literals;
+
+using testing::_;
+using testing::AnyNumber;
+using testing::ByMove;
+using testing::DoAll;
+using testing::Invoke;
+using testing::SaveArg;
+
+using broadcastradio::vts::CallBarrier;
+using V1_0::BandConfig;
+using V1_0::Class;
+using V1_0::MetaData;
+using V1_0::MetadataKey;
+using V1_0::MetadataType;
+using V1_1::IBroadcastRadio;
+using V1_1::ProgramInfo;
+using V1_1::ProgramListResult;
+using V1_1::ProgramSelector;
+using V1_1::Properties;
+
+using broadcastradio::vts::clearAndWait;
+
+static constexpr auto kConfigTimeout = 10s;
+static constexpr auto kConnectModuleTimeout = 1s;
+
+static void printSkipped(std::string msg) {
+    std::cout << "[  SKIPPED ] " << msg << std::endl;
+}
+
+struct TunerCallbackMock : public ITunerCallback {
+    TunerCallbackMock() { EXPECT_CALL(*this, hardwareFailure()).Times(0); }
+
+    MOCK_METHOD0(hardwareFailure, Return<void>());
+    MOCK_TIMEOUT_METHOD2(configChange, Return<void>(Result, const BandConfig&));
+    MOCK_METHOD2(tuneComplete, Return<void>(Result, const V1_0::ProgramInfo&));
+    MOCK_TIMEOUT_METHOD2(tuneComplete_1_1, Return<void>(Result, const ProgramSelector&));
+    MOCK_METHOD1(afSwitch, Return<void>(const V1_0::ProgramInfo&));
+    MOCK_METHOD1(antennaStateChange, Return<void>(bool connected));
+    MOCK_METHOD1(trafficAnnouncement, Return<void>(bool active));
+    MOCK_METHOD1(emergencyAnnouncement, Return<void>(bool active));
+    MOCK_METHOD3(newMetadata, Return<void>(uint32_t ch, uint32_t subCh, const hidl_vec<MetaData>&));
+    MOCK_METHOD1(backgroundScanAvailable, Return<void>(bool));
+    MOCK_TIMEOUT_METHOD1(backgroundScanComplete, Return<void>(ProgramListResult));
+    MOCK_METHOD0(programListChanged, Return<void>());
+    MOCK_TIMEOUT_METHOD1(currentProgramInfoChanged, Return<void>(const ProgramInfo&));
+    MOCK_METHOD1(parametersUpdated, Return<void>(const hidl_vec<VendorKeyValue>& parameters));
+};
+
+class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase,
+                              public ::testing::WithParamInterface<Class> {
+   protected:
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+
+    bool openTuner();
+
+    Class radioClass;
+    bool skipped = false;
+
+    sp<IBroadcastRadio> mRadioModule;
+    sp<ITuner> mTuner;
+    sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
+
+   private:
+    const BandConfig& getBand(unsigned idx);
+
+    hidl_vec<BandConfig> mBands;
+};
+
+void BroadcastRadioHalTest::SetUp() {
+    radioClass = GetParam();
+
+    // lookup HIDL service
+    auto factory = getService<IBroadcastRadioFactory>();
+    ASSERT_NE(nullptr, factory.get());
+
+    // connect radio module
+    Result connectResult;
+    CallBarrier onConnect;
+    factory->connectModule(radioClass, [&](Result ret, const sp<V1_0::IBroadcastRadio>& radio) {
+        connectResult = ret;
+        if (ret == Result::OK) mRadioModule = IBroadcastRadio::castFrom(radio);
+        onConnect.call();
+    });
+    ASSERT_TRUE(onConnect.waitForCall(kConnectModuleTimeout));
+
+    if (connectResult == Result::INVALID_ARGUMENTS) {
+        printSkipped("This device class is not supported.");
+        skipped = true;
+        return;
+    }
+    ASSERT_EQ(connectResult, Result::OK);
+    ASSERT_NE(nullptr, mRadioModule.get());
+
+    // get module properties
+    Properties prop11;
+    auto& prop10 = prop11.base;
+    auto propResult =
+        mRadioModule->getProperties_1_1([&](const Properties& properties) { prop11 = properties; });
+
+    ASSERT_TRUE(propResult.isOk());
+    EXPECT_EQ(radioClass, prop10.classId);
+    EXPECT_GT(prop10.numTuners, 0u);
+    EXPECT_GT(prop11.supportedProgramTypes.size(), 0u);
+    EXPECT_GT(prop11.supportedIdentifierTypes.size(), 0u);
+    if (radioClass == Class::AM_FM) {
+        EXPECT_GT(prop10.bands.size(), 0u);
+    }
+    mBands = prop10.bands;
+}
+
+void BroadcastRadioHalTest::TearDown() {
+    mTuner.clear();
+    mRadioModule.clear();
+    clearAndWait(mCallback, 1s);
+}
+
+bool BroadcastRadioHalTest::openTuner() {
+    EXPECT_EQ(nullptr, mTuner.get());
+
+    if (radioClass == Class::AM_FM) {
+        EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _);
+    }
+
+    Result halResult = Result::NOT_INITIALIZED;
+    auto openCb = [&](Result result, const sp<V1_0::ITuner>& tuner) {
+        halResult = result;
+        if (result != Result::OK) return;
+        mTuner = ITuner::castFrom(tuner);
+    };
+    auto hidlResult = mRadioModule->openTuner(getBand(0), true, mCallback, openCb);
+
+    EXPECT_TRUE(hidlResult.isOk());
+    EXPECT_EQ(Result::OK, halResult);
+    EXPECT_NE(nullptr, mTuner.get());
+    if (radioClass == Class::AM_FM && mTuner != nullptr) {
+        EXPECT_TIMEOUT_CALL_WAIT(*mCallback, configChange, kConfigTimeout);
+
+        BandConfig halConfig;
+        Result halResult = Result::NOT_INITIALIZED;
+        mTuner->getConfiguration([&](Result result, const BandConfig& config) {
+            halResult = result;
+            halConfig = config;
+        });
+        EXPECT_EQ(Result::OK, halResult);
+        EXPECT_TRUE(halConfig.antennaConnected);
+    }
+
+    EXPECT_NE(nullptr, mTuner.get());
+    return nullptr != mTuner.get();
+}
+
+const BandConfig& BroadcastRadioHalTest::getBand(unsigned idx) {
+    static const BandConfig dummyBandConfig = {};
+
+    if (radioClass != Class::AM_FM) {
+        ALOGD("Not AM/FM radio, returning dummy band config");
+        return dummyBandConfig;
+    }
+
+    EXPECT_GT(mBands.size(), idx);
+    if (mBands.size() <= idx) {
+        ALOGD("Band index out of bound, returning dummy band config");
+        return dummyBandConfig;
+    }
+
+    auto& band = mBands[idx];
+    ALOGD("Returning %s band", toString(band.type).c_str());
+    return band;
+}
+
+/**
+ * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
+ *
+ * Verifies that:
+ *  - callback is called for empty parameters set.
+ */
+TEST_P(BroadcastRadioHalTest, NoParameters) {
+    if (skipped) return;
+
+    ASSERT_TRUE(openTuner());
+
+    hidl_vec<VendorKeyValue> halResults = {};
+    bool wasCalled = false;
+    auto cb = [&](hidl_vec<VendorKeyValue> results) {
+        wasCalled = true;
+        halResults = results;
+    };
+
+    auto hidlResult = mTuner->setParameters({}, cb);
+    ASSERT_TRUE(hidlResult.isOk());
+    ASSERT_TRUE(wasCalled);
+    ASSERT_EQ(0u, halResults.size());
+
+    wasCalled = false;
+    hidlResult = mTuner->getParameters({}, cb);
+    ASSERT_TRUE(hidlResult.isOk());
+    ASSERT_TRUE(wasCalled);
+    ASSERT_EQ(0u, halResults.size());
+}
+
+/**
+ * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
+ *
+ * Verifies that:
+ *  - unknown parameters are ignored;
+ *  - callback is called also for empty results set.
+ */
+TEST_P(BroadcastRadioHalTest, UnknownParameters) {
+    if (skipped) return;
+
+    ASSERT_TRUE(openTuner());
+
+    hidl_vec<VendorKeyValue> halResults = {};
+    bool wasCalled = false;
+    auto cb = [&](hidl_vec<VendorKeyValue> results) {
+        wasCalled = true;
+        halResults = results;
+    };
+
+    auto hidlResult = mTuner->setParameters({{"com.google.unknown", "dummy"}}, cb);
+    ASSERT_TRUE(hidlResult.isOk());
+    ASSERT_TRUE(wasCalled);
+    ASSERT_EQ(0u, halResults.size());
+
+    wasCalled = false;
+    hidlResult = mTuner->getParameters({{"com.google.unknown*", "dummy"}}, cb);
+    ASSERT_TRUE(hidlResult.isOk());
+    ASSERT_TRUE(wasCalled);
+    ASSERT_EQ(0u, halResults.size());
+}
+
+// TODO(b/69860743): implement VerifyIdentifiersFormat test when
+// the new program list fetching mechanism is implemented
+
+INSTANTIATE_TEST_CASE_P(BroadcastRadioHalTestCases, BroadcastRadioHalTest,
+                        ::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
+
+}  // namespace vts
+}  // namespace V1_2
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  int status = RUN_ALL_TESTS();
+  ALOGI("Test result = %d", status);
+  return status;
+}
diff --git a/broadcastradio/2.0/Android.bp b/broadcastradio/2.0/Android.bp
new file mode 100644
index 0000000..2434fdc
--- /dev/null
+++ b/broadcastradio/2.0/Android.bp
@@ -0,0 +1,45 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.broadcastradio@2.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IAnnouncementListener.hal",
+        "IBroadcastRadio.hal",
+        "ICloseHandle.hal",
+        "ITunerCallback.hal",
+        "ITunerSession.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "AmFmBandRange",
+        "AmFmRegionConfig",
+        "Announcement",
+        "AnnouncementType",
+        "ConfigFlag",
+        "Constants",
+        "DabTableEntry",
+        "Deemphasis",
+        "IdentifierType",
+        "Metadata",
+        "MetadataKey",
+        "ProgramFilter",
+        "ProgramIdentifier",
+        "ProgramInfo",
+        "ProgramInfoFlags",
+        "ProgramListChunk",
+        "ProgramSelector",
+        "Properties",
+        "Rds",
+        "Result",
+        "VendorKeyValue",
+    ],
+    gen_java: true,
+}
+
diff --git a/broadcastradio/2.0/IAnnouncementListener.hal b/broadcastradio/2.0/IAnnouncementListener.hal
new file mode 100644
index 0000000..1b4960c
--- /dev/null
+++ b/broadcastradio/2.0/IAnnouncementListener.hal
@@ -0,0 +1,30 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio@2.0;
+
+/**
+ * Callback interface for announcement listener.
+ *
+ * For typical configuration, the listener is a broadcast radio service.
+ */
+interface IAnnouncementListener {
+    /**
+     * Called whenever announcement list has changed.
+     *
+     * @param announcements The complete list of currently active announcements.
+     */
+    oneway onListUpdated(vec<Announcement> announcements);
+};
diff --git a/broadcastradio/2.0/IBroadcastRadio.hal b/broadcastradio/2.0/IBroadcastRadio.hal
new file mode 100644
index 0000000..bedc362
--- /dev/null
+++ b/broadcastradio/2.0/IBroadcastRadio.hal
@@ -0,0 +1,129 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio@2.0;
+
+import IAnnouncementListener;
+import ICloseHandle;
+import ITunerCallback;
+import ITunerSession;
+
+/**
+ * Represents a hardware broadcast radio module. A single module may contain
+ * multiple hardware tuners (i.e. with an additional background tuner), but the
+ * layers above the HAL see them as a single logical unit.
+ */
+interface IBroadcastRadio {
+    /**
+     * Returns module properties: a description of a module and its
+     * capabilities. This method must not fail.
+     *
+     * @return properties Module description.
+     */
+    getProperties() generates (Properties properties);
+
+    /**
+     * Fetches current or possible AM/FM region configuration.
+     *
+     * @param full If true, returns full hardware capabilities.
+     *             If false, returns current regional configuration.
+     * @return result OK in case of success.
+     *                NOT_SUPPORTED if the tuner doesn't support AM/FM.
+     * @return config Hardware capabilities (full=true) or
+     *                current configuration (full=false).
+     */
+    getAmFmRegionConfig(bool full)
+            generates (Result result, AmFmRegionConfig config);
+
+    /**
+     * Fetches current DAB region configuration.
+     *
+     * @return result OK in case of success.
+     *                NOT_SUPPORTED if the tuner doesn't support DAB.
+     * @return config Current configuration.
+     */
+    getDabRegionConfig() generates (Result result, vec<DabTableEntry> config);
+
+    /**
+     * Opens a new tuner session.
+     *
+     * There may be only one session active at a time. If the new session was
+     * requested when the old one was active, the old must be terminated
+     * (aggressive open).
+     *
+     * @param callback The callback interface.
+     * @return result OK in case of success.
+     * @return session The session interface.
+     */
+    openSession(ITunerCallback callback)
+        generates (Result result, ITunerSession session);
+
+    /**
+     * Fetch image from radio module cache.
+     *
+     * This is out-of-band transport mechanism for images carried with metadata.
+     * The metadata vector only passes the identifier, so the client may cache
+     * images or even not fetch them.
+     *
+     * The identifier may be any arbitrary number (i.e. sha256 prefix) selected
+     * by the vendor. It must be stable across sessions so the application may
+     * cache it.
+     *
+     * The data must be a valid PNG, JPEG, GIF or BMP file.
+     * Image data with an invalid format must be handled gracefully in the same
+     * way as a missing image.
+     *
+     * The image identifier may become invalid after some time from passing it
+     * with metadata struct (due to resource cleanup at the HAL implementation).
+     * However, it must remain valid for a currently tuned program at least
+     * until onCurrentProgramInfoChanged is called.
+     *
+     * There is still a race condition possible between
+     * onCurrentProgramInfoChanged callback and the HAL implementation eagerly
+     * clearing the cache (because the next onCurrentProgramInfoChanged came).
+     * In such case, client application may expect the new
+     * onCurrentProgramInfoChanged callback with updated image identifier.
+     *
+     * @param id Identifier of an image (value of Constants::INVALID_IMAGE is
+     *           reserved and must be treated as invalid image).
+     * @return image A binary blob with image data
+     *               or a zero-length vector if identifier doesn't exist.
+     */
+    getImage(uint32_t id) generates (vec<uint8_t> image);
+
+    /**
+     * Registers announcement listener.
+     *
+     * If there is at least one observer registered, HAL implementation must
+     * notify about announcements even if no sessions are active.
+     *
+     * If the observer dies, the HAL implementation must unregister observer
+     * automatically.
+     *
+     * @param enabled The list of announcement types to watch for.
+     * @param listener The listener interface.
+     * @return result OK in case of success.
+     *                NOT_SUPPORTED if the tuner doesn't support announcements.
+     * @return closeHandle A handle to unregister observer,
+     *                     nullptr if result was not OK.
+     */
+    registerAnnouncementListener(
+            vec<AnnouncementType> enabled,
+            IAnnouncementListener listener
+        ) generates (
+            Result result,
+            ICloseHandle closeHandle
+        );
+};
diff --git a/broadcastradio/2.0/ICloseHandle.hal b/broadcastradio/2.0/ICloseHandle.hal
new file mode 100644
index 0000000..34cea14
--- /dev/null
+++ b/broadcastradio/2.0/ICloseHandle.hal
@@ -0,0 +1,32 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio@2.0;
+
+/**
+ * Represents a generic close handle to remove a callback that doesn't need
+ * active interface.
+ */
+interface ICloseHandle {
+    /**
+     * Closes the handle.
+     *
+     * The call must not fail and must only be issued once.
+     *
+     * After the close call is executed, no other calls to this interface
+     * are allowed.
+     */
+    close();
+};
diff --git a/broadcastradio/2.0/ITunerCallback.hal b/broadcastradio/2.0/ITunerCallback.hal
new file mode 100644
index 0000000..ede8350
--- /dev/null
+++ b/broadcastradio/2.0/ITunerCallback.hal
@@ -0,0 +1,82 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio@2.0;
+
+interface ITunerCallback {
+    /**
+     * Method called by the HAL when a tuning operation fails
+     * following a step(), scan() or tune() command.
+     *
+     * @param result OK if tune succeeded;
+     *               TIMEOUT in case of time out.
+     * @param selector A ProgramSelector structure passed from tune(),
+     *                 empty for step() and scan().
+     */
+    oneway onTuneFailed(Result result, ProgramSelector selector);
+
+    /**
+     * Method called by the HAL when current program information (including
+     * metadata) is updated.
+     *
+     * This is also called when the radio tuned to the static (not a valid
+     * station), see the TUNED flag of ProgramInfoFlags.
+     *
+     * @param info Current program information.
+     */
+    oneway onCurrentProgramInfoChanged(ProgramInfo info);
+
+    /**
+     * A delta update of the program list, called whenever there's a change in
+     * the list.
+     *
+     * If there are frequent changes, HAL implementation must throttle the rate
+     * of the updates.
+     *
+     * There is a hard limit on binder transaction buffer, and the list must
+     * not exceed it. For large lists, HAL implementation must split them to
+     * multiple chunks, no larger than 500kiB each.
+     *
+     * @param chunk A chunk of the program list update.
+     */
+    oneway onProgramListUpdated(ProgramListChunk chunk);
+
+    /**
+     * Method called by the HAL when the antenna gets connected or disconnected.
+     *
+     * For a new tuner session, client must assume the antenna is connected.
+     * If it's not, then antennaStateChange must be called within
+     * Constants::ANTENNA_DISCONNECTED_TIMEOUT_MS to indicate that.
+     *
+     * @param connected True if the antenna is now connected, false otherwise.
+     */
+    oneway onAntennaStateChange(bool connected);
+
+    /**
+     * Generic callback for passing updates to vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * It's up to the HAL implementation if and how to implement this callback,
+     * as long as it obeys the prefix rule. In particular, only selected keys
+     * may be notified this way. However, setParameters must not trigger
+     * this callback, while an internal event can change parameters
+     * asynchronously.
+     *
+     * @param parameters Vendor-specific key-value pairs,
+     *                   opaque to Android framework.
+     */
+    oneway onParametersUpdated(vec<VendorKeyValue> parameters);
+};
diff --git a/broadcastradio/2.0/ITunerSession.hal b/broadcastradio/2.0/ITunerSession.hal
new file mode 100644
index 0000000..e891a23
--- /dev/null
+++ b/broadcastradio/2.0/ITunerSession.hal
@@ -0,0 +1,189 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio@2.0;
+
+interface ITunerSession {
+    /**
+     * Tune to a specified program.
+     *
+     * Automatically cancels pending scan, step or tune.
+     * If the method returns OK, tuneFailed or currentProgramInfoChanged
+     * callback must be called.
+     *
+     * @param program Program to tune to.
+     * @return result OK if successfully started tuning.
+     *                NOT_SUPPORTED if the program selector doesn't contain any
+     *                supported identifier.
+     *                INVALID_ARGUMENTS if the program selector contains
+     *                identifiers in invalid format (i.e. out of range).
+     */
+    tune(ProgramSelector program) generates (Result result);
+
+    /**
+     * Tune to the next valid program.
+     *
+     * Automatically cancels pending scan, step or tune.
+     * If the method returns OK, tuneFailed or currentProgramInfoChanged
+     * callback must be called.
+     *
+     * The skipSubChannel parameter is used to skip digital radio subchannels:
+     *  - HD Radio SPS;
+     *  - DAB secondary service.
+     *
+     * As an implementation detail, the HAL has the option to perform an actual
+     * scan or select the next program from the list retrieved in the
+     * background, if one is not stale.
+     *
+     * @param directionUp True to change towards higher numeric values
+     *                    (frequency, channel number), false towards lower.
+     * @param skipSubChannel Don't tune to subchannels.
+     * @return result OK if the scan has successfully started.
+     */
+    scan(bool directionUp, bool skipSubChannel) generates (Result result);
+
+    /**
+     * Tune to the adjacent channel, which may not be occupied by any program.
+     *
+     * Automatically cancels pending scan, step or tune.
+     * If the method returns OK, tuneFailed or currentProgramInfoChanged
+     * callback must be called.
+     *
+     * @param directionUp True to change towards higher numeric values
+     *                    (frequency, channel number), false towards lower.
+     * @return result OK successfully started tuning.
+     *                NOT_SUPPORTED if tuning to an unoccupied channel is not
+     *                supported (i.e. for satellite radio).
+     */
+    step(bool directionUp) generates (Result result);
+
+    /**
+     * Cancel a scan, step or tune operation.
+     *
+     * If there is no such operation running, the call must be ignored.
+     */
+    cancel();
+
+    /**
+     * Applies a filter to the program list and starts sending program list
+     * updates over onProgramListUpdated callback.
+     *
+     * There may be only one updates stream active at the moment. Calling this
+     * method again must result in cancelling the previous update request.
+     *
+     * This call clears the program list on the client side, the HAL must send
+     * the whole list again.
+     *
+     * If the program list scanning hardware (i.e. background tuner) is
+     * unavailable at the moment, the call must succeed and start updates
+     * when it becomes available.
+     *
+     * @param filter Filter to apply on the fetched program list.
+     * @return result OK successfully started fetching list updates.
+     *                NOT_SUPPORTED program list scanning is not supported
+     *                by the hardware.
+     */
+    startProgramListUpdates(ProgramFilter filter) generates (Result result);
+
+    /**
+     * Stops sending program list updates.
+     */
+    stopProgramListUpdates();
+
+    /**
+     * Fetches the current setting of a given config flag.
+     *
+     * The success/failure result must be consistent with setConfigFlag.
+     *
+     * @param flag Flag to fetch.
+     * @return result OK successfully fetched the flag.
+     *                INVALID_STATE if the flag is not applicable right now.
+     *                NOT_SUPPORTED if the flag is not supported at all.
+     * @return value The current value of the flag, if result is OK.
+     */
+    isConfigFlagSet(ConfigFlag flag) generates (Result result, bool value);
+
+    /**
+     * Sets the config flag.
+     *
+     * The success/failure result must be consistent with isConfigFlagSet.
+     *
+     * @param flag Flag to set.
+     * @param value The new value of a given flag.
+     * @return result OK successfully set the flag.
+     *                INVALID_STATE if the flag is not applicable right now.
+     *                NOT_SUPPORTED if the flag is not supported at all.
+     */
+    setConfigFlag(ConfigFlag flag, bool value) generates (Result result);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Framework does not make any assumptions on the keys or values, other than
+     * ones stated in VendorKeyValue documentation (a requirement of key
+     * prefixes).
+     *
+     * For each pair in the result vector, the key must be one of the keys
+     * contained in the input (possibly with wildcards expanded), and the value
+     * must be a vendor-specific result status (i.e. the string "OK" or an error
+     * code). The implementation may choose to return an empty vector, or only
+     * return a status for a subset of the provided inputs, at its discretion.
+     *
+     * Application and HAL must not use keys with unknown prefix. In particular,
+     * it must not place a key-value pair in results vector for unknown key from
+     * parameters vector - instead, an unknown key should simply be ignored.
+     * In other words, results vector may contain a subset of parameter keys
+     * (however, the framework doesn't enforce a strict subset - the only
+     * formal requirement is vendor domain prefix for keys).
+     *
+     * @param parameters Vendor-specific key-value pairs.
+     * @return results Operation completion status for parameters being set.
+     */
+    setParameters(vec<VendorKeyValue> parameters)
+        generates (vec<VendorKeyValue> results);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * Framework does not cache set/get requests, so it's allowed for
+     * getParameter to return a different value than previous setParameter call.
+     *
+     * The syntax and semantics of keys are up to the vendor (as long as prefix
+     * rules are obeyed). For instance, vendors may include some form of
+     * wildcard support. In such case, result vector may be of different size
+     * than requested keys vector. However, wildcards are not recognized by
+     * framework and they are passed as-is to the HAL implementation.
+     *
+     * Unknown keys must be ignored and not placed into results vector.
+     *
+     * @param keys Parameter keys to fetch.
+     * @return parameters Vendor-specific key-value pairs.
+     */
+    getParameters(vec<string> keys) generates (vec<VendorKeyValue> parameters);
+
+    /**
+     * Closes the session.
+     *
+     * The call must not fail and must only be issued once.
+     *
+     * After the close call is executed, no other calls to this interface
+     * are allowed.
+     */
+    close();
+};
diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp
new file mode 100644
index 0000000..900454e
--- /dev/null
+++ b/broadcastradio/2.0/default/Android.bp
@@ -0,0 +1,49 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+    name: "android.hardware.broadcastradio@2.0-service",
+    init_rc: ["android.hardware.broadcastradio@2.0-service.rc"],
+    vendor: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    cppflags: [
+        "-std=c++1z",
+    ],
+    srcs: [
+        "BroadcastRadio.cpp",
+        "TunerSession.cpp",
+        "VirtualProgram.cpp",
+        "VirtualRadio.cpp",
+        "service.cpp"
+    ],
+    static_libs: [
+        "android.hardware.broadcastradio@common-utils-2x-lib",
+        "android.hardware.broadcastradio@common-utils-lib",
+    ],
+    shared_libs: [
+        "android.hardware.broadcastradio@2.0",
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/broadcastradio/2.0/default/BroadcastRadio.cpp b/broadcastradio/2.0/default/BroadcastRadio.cpp
new file mode 100644
index 0000000..0148fec
--- /dev/null
+++ b/broadcastradio/2.0/default/BroadcastRadio.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BcRadioDef.module"
+#define LOG_NDEBUG 0
+
+#include "BroadcastRadio.h"
+
+#include <log/log.h>
+
+#include "resources.h"
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+using std::lock_guard;
+using std::map;
+using std::mutex;
+using std::vector;
+
+static const AmFmRegionConfig gDefaultAmFmConfig = {  //
+    {
+        {87500, 108000, 100, 100},  // FM
+        {153, 282, 3, 9},           // AM LW
+        {531, 1620, 9, 9},          // AM MW
+        {1600, 30000, 1, 5},        // AM SW
+    },
+    static_cast<uint32_t>(Deemphasis::D50),
+    static_cast<uint32_t>(Rds::RDS)};
+
+static Properties initProperties(const VirtualRadio& virtualRadio) {
+    Properties prop = {};
+
+    prop.maker = "Google";
+    prop.product = virtualRadio.getName();
+    prop.supportedIdentifierTypes = hidl_vec<uint32_t>({
+        static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY),
+        static_cast<uint32_t>(IdentifierType::RDS_PI),
+        static_cast<uint32_t>(IdentifierType::HD_STATION_ID_EXT),
+    });
+    prop.vendorInfo = hidl_vec<VendorKeyValue>({
+        {"com.google.dummy", "dummy"},
+    });
+
+    return prop;
+}
+
+BroadcastRadio::BroadcastRadio(const VirtualRadio& virtualRadio)
+    : mVirtualRadio(virtualRadio),
+      mProperties(initProperties(virtualRadio)),
+      mAmFmConfig(gDefaultAmFmConfig) {}
+
+Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    _hidl_cb(mProperties);
+    return {};
+}
+
+AmFmRegionConfig BroadcastRadio::getAmFmConfig() const {
+    lock_guard<mutex> lk(mMut);
+    return mAmFmConfig;
+}
+
+Return<void> BroadcastRadio::getAmFmRegionConfig(bool full, getAmFmRegionConfig_cb _hidl_cb) {
+    ALOGV("%s(%d)", __func__, full);
+
+    if (full) {
+        AmFmRegionConfig config = {};
+        config.ranges = hidl_vec<AmFmBandRange>({
+            {65000, 108000, 10, 0},  // FM
+            {150, 30000, 1, 0},      // AM
+        });
+        config.fmDeemphasis = Deemphasis::D50 | Deemphasis::D75;
+        config.fmRds = Rds::RDS | Rds::RBDS;
+        _hidl_cb(Result::OK, config);
+        return {};
+    } else {
+        _hidl_cb(Result::OK, getAmFmConfig());
+        return {};
+    }
+}
+
+Return<void> BroadcastRadio::getDabRegionConfig(getDabRegionConfig_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+
+    hidl_vec<DabTableEntry> config = {
+        {"5A", 174928},  {"7D", 194064},  {"8A", 195936},  {"8B", 197648},  {"9A", 202928},
+        {"9B", 204640},  {"9C", 206352},  {"10B", 211648}, {"10C", 213360}, {"10D", 215072},
+        {"11A", 216928}, {"11B", 218640}, {"11C", 220352}, {"11D", 222064}, {"12A", 223936},
+        {"12B", 225648}, {"12C", 227360}, {"12D", 229072},
+    };
+
+    _hidl_cb(Result::OK, config);
+    return {};
+}
+
+Return<void> BroadcastRadio::openSession(const sp<ITunerCallback>& callback,
+                                         openSession_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+
+    /* For the needs of default implementation it's fine to instantiate new session object
+     * out of the lock scope. If your implementation needs it, use reentrant lock.
+     */
+    sp<TunerSession> newSession = new TunerSession(*this, callback);
+
+    lock_guard<mutex> lk(mMut);
+
+    auto oldSession = mSession.promote();
+    if (oldSession != nullptr) {
+        ALOGI("Closing previously opened tuner");
+        oldSession->close();
+        mSession = nullptr;
+    }
+
+    mSession = newSession;
+
+    _hidl_cb(Result::OK, newSession);
+    return {};
+}
+
+Return<void> BroadcastRadio::getImage(uint32_t id, getImage_cb _hidl_cb) {
+    ALOGV("%s(%x)", __func__, id);
+
+    if (id == resources::demoPngId) {
+        _hidl_cb(std::vector<uint8_t>(resources::demoPng, std::end(resources::demoPng)));
+        return {};
+    }
+
+    ALOGI("Image %x doesn't exists", id);
+    _hidl_cb({});
+    return {};
+}
+
+Return<void> BroadcastRadio::registerAnnouncementListener(
+    const hidl_vec<AnnouncementType>& enabled, const sp<IAnnouncementListener>& /* listener */,
+    registerAnnouncementListener_cb _hidl_cb) {
+    ALOGV("%s(%s)", __func__, toString(enabled).c_str());
+
+    _hidl_cb(Result::NOT_SUPPORTED, nullptr);
+    return {};
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/2.0/default/BroadcastRadio.h b/broadcastradio/2.0/default/BroadcastRadio.h
new file mode 100644
index 0000000..8c14d9e
--- /dev/null
+++ b/broadcastradio/2.0/default/BroadcastRadio.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V2_0_BROADCASTRADIO_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V2_0_BROADCASTRADIO_H
+
+#include "TunerSession.h"
+
+#include <android/hardware/broadcastradio/2.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+struct BroadcastRadio : public IBroadcastRadio {
+    BroadcastRadio(const VirtualRadio& virtualRadio);
+
+    // V2_0::IBroadcastRadio methods
+    Return<void> getProperties(getProperties_cb _hidl_cb) override;
+    Return<void> getAmFmRegionConfig(bool full, getAmFmRegionConfig_cb _hidl_cb);
+    Return<void> getDabRegionConfig(getDabRegionConfig_cb _hidl_cb);
+    Return<void> openSession(const sp<ITunerCallback>& callback, openSession_cb _hidl_cb) override;
+    Return<void> getImage(uint32_t id, getImage_cb _hidl_cb);
+    Return<void> registerAnnouncementListener(const hidl_vec<AnnouncementType>& enabled,
+                                              const sp<IAnnouncementListener>& listener,
+                                              registerAnnouncementListener_cb _hidl_cb);
+
+    std::reference_wrapper<const VirtualRadio> mVirtualRadio;
+    Properties mProperties;
+
+    AmFmRegionConfig getAmFmConfig() const;
+
+   private:
+    mutable std::mutex mMut;
+    AmFmRegionConfig mAmFmConfig;
+    wp<TunerSession> mSession;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V2_0_BROADCASTRADIO_H
diff --git a/broadcastradio/2.0/default/OWNERS b/broadcastradio/2.0/default/OWNERS
new file mode 100644
index 0000000..136b607
--- /dev/null
+++ b/broadcastradio/2.0/default/OWNERS
@@ -0,0 +1,3 @@
+# Automotive team
+egranata@google.com
+twasilczyk@google.com
diff --git a/broadcastradio/2.0/default/TunerSession.cpp b/broadcastradio/2.0/default/TunerSession.cpp
new file mode 100644
index 0000000..56a3508
--- /dev/null
+++ b/broadcastradio/2.0/default/TunerSession.cpp
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BcRadioDef.tuner"
+#define LOG_NDEBUG 0
+
+#include "TunerSession.h"
+
+#include "BroadcastRadio.h"
+
+#include <broadcastradio-utils-2x/Utils.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+using namespace std::chrono_literals;
+
+using utils::tunesTo;
+
+using std::lock_guard;
+using std::move;
+using std::mutex;
+using std::sort;
+using std::vector;
+
+namespace delay {
+
+static constexpr auto scan = 200ms;
+static constexpr auto step = 100ms;
+static constexpr auto tune = 150ms;
+static constexpr auto list = 1s;
+
+}  // namespace delay
+
+TunerSession::TunerSession(BroadcastRadio& module, const sp<ITunerCallback>& callback)
+    : mCallback(callback), mModule(module) {
+    auto&& ranges = module.getAmFmConfig().ranges;
+    if (ranges.size() > 0) {
+        tuneInternalLocked(utils::make_selector_amfm(ranges[0].lowerBound));
+    }
+}
+
+// makes ProgramInfo that points to no program
+static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) {
+    ProgramInfo info = {};
+    info.selector = selector;
+    info.logicallyTunedTo = utils::make_identifier(
+        IdentifierType::AMFM_FREQUENCY, utils::getId(selector, IdentifierType::AMFM_FREQUENCY));
+    info.physicallyTunedTo = info.logicallyTunedTo;
+    return info;
+}
+
+void TunerSession::tuneInternalLocked(const ProgramSelector& sel) {
+    ALOGV("%s(%s)", __func__, toString(sel).c_str());
+
+    VirtualProgram virtualProgram;
+    ProgramInfo programInfo;
+    if (virtualRadio().getProgram(sel, virtualProgram)) {
+        mCurrentProgram = virtualProgram.selector;
+        programInfo = virtualProgram;
+    } else {
+        mCurrentProgram = sel;
+        programInfo = makeDummyProgramInfo(sel);
+    }
+    mIsTuneCompleted = true;
+
+    mCallback->onCurrentProgramInfoChanged(programInfo);
+}
+
+const BroadcastRadio& TunerSession::module() const {
+    return mModule.get();
+}
+
+const VirtualRadio& TunerSession::virtualRadio() const {
+    return module().mVirtualRadio;
+}
+
+Return<Result> TunerSession::tune(const ProgramSelector& sel) {
+    ALOGV("%s(%s)", __func__, toString(sel).c_str());
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::INVALID_STATE;
+
+    if (!utils::isSupported(module().mProperties, sel)) {
+        ALOGW("Selector not supported");
+        return Result::NOT_SUPPORTED;
+    }
+
+    if (!utils::isValid(sel)) {
+        ALOGE("ProgramSelector is not valid");
+        return Result::INVALID_ARGUMENTS;
+    }
+
+    cancelLocked();
+
+    mIsTuneCompleted = false;
+    auto task = [this, sel]() {
+        lock_guard<mutex> lk(mMut);
+        tuneInternalLocked(sel);
+    };
+    mThread.schedule(task, delay::tune);
+
+    return Result::OK;
+}
+
+Return<Result> TunerSession::scan(bool directionUp, bool /* skipSubChannel */) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::INVALID_STATE;
+
+    cancelLocked();
+
+    auto list = virtualRadio().getProgramList();
+
+    if (list.empty()) {
+        mIsTuneCompleted = false;
+        auto task = [this, directionUp]() {
+            ALOGI("Performing failed scan up=%d", directionUp);
+
+            mCallback->onTuneFailed(Result::TIMEOUT, {});
+        };
+        mThread.schedule(task, delay::scan);
+
+        return Result::OK;
+    }
+
+    // Not optimal (O(sort) instead of O(n)), but not a big deal here;
+    // also, it's likely that list is already sorted (so O(n) anyway).
+    sort(list.begin(), list.end());
+    auto current = mCurrentProgram;
+    auto found = lower_bound(list.begin(), list.end(), VirtualProgram({current}));
+    if (directionUp) {
+        if (found < list.end() - 1) {
+            if (tunesTo(current, found->selector)) found++;
+        } else {
+            found = list.begin();
+        }
+    } else {
+        if (found > list.begin() && found != list.end()) {
+            found--;
+        } else {
+            found = list.end() - 1;
+        }
+    }
+    auto tuneTo = found->selector;
+
+    mIsTuneCompleted = false;
+    auto task = [this, tuneTo, directionUp]() {
+        ALOGI("Performing scan up=%d", directionUp);
+
+        lock_guard<mutex> lk(mMut);
+        tuneInternalLocked(tuneTo);
+    };
+    mThread.schedule(task, delay::scan);
+
+    return Result::OK;
+}
+
+Return<Result> TunerSession::step(bool directionUp) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::INVALID_STATE;
+
+    cancelLocked();
+
+    if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) {
+        ALOGE("Can't step in anything else than AM/FM");
+        return Result::NOT_SUPPORTED;
+    }
+
+    auto stepTo = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY);
+    auto range = getAmFmRangeLocked();
+    if (!range) {
+        ALOGE("Can't find current band");
+        return Result::INTERNAL_ERROR;
+    }
+
+    if (directionUp) {
+        stepTo += range->spacing;
+    } else {
+        stepTo -= range->spacing;
+    }
+    if (stepTo > range->upperBound) stepTo = range->lowerBound;
+    if (stepTo < range->lowerBound) stepTo = range->upperBound;
+
+    mIsTuneCompleted = false;
+    auto task = [this, stepTo]() {
+        ALOGI("Performing step to %s", std::to_string(stepTo).c_str());
+
+        lock_guard<mutex> lk(mMut);
+
+        tuneInternalLocked(utils::make_selector_amfm(stepTo));
+    };
+    mThread.schedule(task, delay::step);
+
+    return Result::OK;
+}
+
+void TunerSession::cancelLocked() {
+    ALOGV("%s", __func__);
+
+    mThread.cancelAll();
+    if (utils::getType(mCurrentProgram.primaryId) != IdentifierType::INVALID) {
+        mIsTuneCompleted = true;
+    }
+}
+
+Return<void> TunerSession::cancel() {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return {};
+
+    cancelLocked();
+
+    return {};
+}
+
+Return<Result> TunerSession::startProgramListUpdates(const ProgramFilter& filter) {
+    ALOGV("%s(%s)", __func__, toString(filter).c_str());
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return Result::INVALID_STATE;
+
+    auto list = virtualRadio().getProgramList();
+    vector<VirtualProgram> filteredList;
+    auto filterCb = [&filter](const VirtualProgram& program) {
+        return utils::satisfies(filter, program.selector);
+    };
+    std::copy_if(list.begin(), list.end(), std::back_inserter(filteredList), filterCb);
+
+    auto task = [this, list]() {
+        lock_guard<mutex> lk(mMut);
+
+        ProgramListChunk chunk = {};
+        chunk.purge = true;
+        chunk.complete = true;
+        chunk.modified = hidl_vec<ProgramInfo>(list.begin(), list.end());
+
+        mCallback->onProgramListUpdated(chunk);
+    };
+    mThread.schedule(task, delay::list);
+
+    return Result::OK;
+}
+
+Return<void> TunerSession::stopProgramListUpdates() {
+    ALOGV("%s", __func__);
+    return {};
+}
+
+Return<void> TunerSession::isConfigFlagSet(ConfigFlag flag, isConfigFlagSet_cb _hidl_cb) {
+    ALOGV("%s(%s)", __func__, toString(flag).c_str());
+
+    _hidl_cb(Result::NOT_SUPPORTED, false);
+    return {};
+}
+
+Return<Result> TunerSession::setConfigFlag(ConfigFlag flag, bool value) {
+    ALOGV("%s(%s, %d)", __func__, toString(flag).c_str(), value);
+
+    return Result::NOT_SUPPORTED;
+}
+
+Return<void> TunerSession::setParameters(const hidl_vec<VendorKeyValue>& /* parameters */,
+                                         setParameters_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+
+    _hidl_cb({});
+    return {};
+}
+
+Return<void> TunerSession::getParameters(const hidl_vec<hidl_string>& /* keys */,
+                                         getParameters_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+
+    _hidl_cb({});
+    return {};
+}
+
+Return<void> TunerSession::close() {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    if (mIsClosed) return {};
+
+    mIsClosed = true;
+    mThread.cancelAll();
+    return {};
+}
+
+std::optional<AmFmBandRange> TunerSession::getAmFmRangeLocked() const {
+    if (!mIsTuneCompleted) {
+        ALOGW("tune operation in process");
+        return {};
+    }
+    if (!utils::hasId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY)) return {};
+
+    auto freq = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY);
+    for (auto&& range : module().getAmFmConfig().ranges) {
+        if (range.lowerBound <= freq && range.upperBound >= freq) return range;
+    }
+
+    return {};
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/2.0/default/TunerSession.h b/broadcastradio/2.0/default/TunerSession.h
new file mode 100644
index 0000000..bf7c607
--- /dev/null
+++ b/broadcastradio/2.0/default/TunerSession.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V2_0_TUNER_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V2_0_TUNER_H
+
+#include "VirtualRadio.h"
+
+#include <android/hardware/broadcastradio/2.0/ITunerCallback.h>
+#include <android/hardware/broadcastradio/2.0/ITunerSession.h>
+#include <broadcastradio-utils/WorkerThread.h>
+
+#include <optional>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+struct BroadcastRadio;
+
+struct TunerSession : public ITunerSession {
+    TunerSession(BroadcastRadio& module, const sp<ITunerCallback>& callback);
+
+    // V2_0::ITunerSession methods
+    virtual Return<Result> tune(const ProgramSelector& program) override;
+    virtual Return<Result> scan(bool directionUp, bool skipSubChannel) override;
+    virtual Return<Result> step(bool directionUp) override;
+    virtual Return<void> cancel() override;
+    virtual Return<Result> startProgramListUpdates(const ProgramFilter& filter);
+    virtual Return<void> stopProgramListUpdates();
+    virtual Return<void> isConfigFlagSet(ConfigFlag flag, isConfigFlagSet_cb _hidl_cb);
+    virtual Return<Result> setConfigFlag(ConfigFlag flag, bool value);
+    virtual Return<void> setParameters(const hidl_vec<VendorKeyValue>& parameters,
+                                       setParameters_cb _hidl_cb) override;
+    virtual Return<void> getParameters(const hidl_vec<hidl_string>& keys,
+                                       getParameters_cb _hidl_cb) override;
+    virtual Return<void> close() override;
+
+    std::optional<AmFmBandRange> getAmFmRangeLocked() const;
+
+   private:
+    std::mutex mMut;
+    WorkerThread mThread;
+    bool mIsClosed = false;
+
+    const sp<ITunerCallback> mCallback;
+
+    std::reference_wrapper<BroadcastRadio> mModule;
+    bool mIsTuneCompleted = false;
+    ProgramSelector mCurrentProgram = {};
+
+    void cancelLocked();
+    void tuneInternalLocked(const ProgramSelector& sel);
+    const VirtualRadio& virtualRadio() const;
+    const BroadcastRadio& module() const;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V2_0_TUNER_H
diff --git a/broadcastradio/2.0/default/VirtualProgram.cpp b/broadcastradio/2.0/default/VirtualProgram.cpp
new file mode 100644
index 0000000..acde704
--- /dev/null
+++ b/broadcastradio/2.0/default/VirtualProgram.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BcRadioDef.VirtualProgram"
+
+#include "VirtualProgram.h"
+
+#include "resources.h"
+
+#include <android-base/logging.h>
+#include <broadcastradio-utils-2x/Utils.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+using utils::getType;
+using utils::make_metadata;
+
+using std::vector;
+
+VirtualProgram::operator ProgramInfo() const {
+    ProgramInfo info = {};
+
+    info.selector = selector;
+
+    auto pType = getType(selector.primaryId);
+    auto isDigital = (pType != IdentifierType::AMFM_FREQUENCY && pType != IdentifierType::RDS_PI);
+
+    auto selectId = [&info](IdentifierType type) {
+        return utils::make_identifier(type, utils::getId(info.selector, type));
+    };
+
+    switch (pType) {
+        case IdentifierType::AMFM_FREQUENCY:
+            info.logicallyTunedTo = info.physicallyTunedTo =
+                selectId(IdentifierType::AMFM_FREQUENCY);
+            break;
+        case IdentifierType::RDS_PI:
+            info.logicallyTunedTo = selectId(IdentifierType::RDS_PI);
+            info.physicallyTunedTo = selectId(IdentifierType::AMFM_FREQUENCY);
+            break;
+        case IdentifierType::HD_STATION_ID_EXT:
+            info.logicallyTunedTo = selectId(IdentifierType::HD_STATION_ID_EXT);
+            info.physicallyTunedTo = selectId(IdentifierType::AMFM_FREQUENCY);
+            break;
+        case IdentifierType::DAB_SID_EXT:
+            info.logicallyTunedTo = selectId(IdentifierType::DAB_SID_EXT);
+            info.physicallyTunedTo = selectId(IdentifierType::DAB_ENSEMBLE);
+            break;
+        case IdentifierType::DRMO_SERVICE_ID:
+            info.logicallyTunedTo = selectId(IdentifierType::DRMO_SERVICE_ID);
+            info.physicallyTunedTo = selectId(IdentifierType::DRMO_FREQUENCY);
+            break;
+        case IdentifierType::SXM_SERVICE_ID:
+            info.logicallyTunedTo = selectId(IdentifierType::SXM_SERVICE_ID);
+            info.physicallyTunedTo = selectId(IdentifierType::SXM_CHANNEL);
+            break;
+        default:
+            LOG(FATAL) << "Unsupported program type: " << toString(pType);
+    }
+
+    info.infoFlags |= ProgramInfoFlags::TUNED;
+    info.infoFlags |= ProgramInfoFlags::STEREO;
+    info.signalQuality = isDigital ? 100 : 80;
+
+    info.metadata = hidl_vec<Metadata>({
+        make_metadata(MetadataKey::RDS_PS, programName),
+        make_metadata(MetadataKey::SONG_TITLE, songTitle),
+        make_metadata(MetadataKey::SONG_ARTIST, songArtist),
+        make_metadata(MetadataKey::STATION_ICON, resources::demoPngId),
+        make_metadata(MetadataKey::ALBUM_ART, resources::demoPngId),
+    });
+
+    info.vendorInfo = hidl_vec<VendorKeyValue>({
+        {"com.google.dummy", "dummy"},
+        {"com.google.dummy.VirtualProgram", std::to_string(reinterpret_cast<uintptr_t>(this))},
+    });
+
+    return info;
+}
+
+bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs) {
+    auto& l = lhs.selector;
+    auto& r = rhs.selector;
+
+    // Two programs with the same primaryId are considered the same.
+    if (l.primaryId.type != r.primaryId.type) return l.primaryId.type < r.primaryId.type;
+    if (l.primaryId.value != r.primaryId.value) return l.primaryId.value < r.primaryId.value;
+
+    return false;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/2.0/default/VirtualProgram.h b/broadcastradio/2.0/default/VirtualProgram.h
new file mode 100644
index 0000000..e1c4f75
--- /dev/null
+++ b/broadcastradio/2.0/default/VirtualProgram.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALPROGRAM_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALPROGRAM_H
+
+#include <android/hardware/broadcastradio/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+/**
+ * A radio program mock.
+ *
+ * This represents broadcast waves flying over the air,
+ * not an entry for a captured station in the radio tuner memory.
+ */
+struct VirtualProgram {
+    ProgramSelector selector;
+
+    std::string programName = "";
+    std::string songArtist = "";
+    std::string songTitle = "";
+
+    operator ProgramInfo() const;
+
+    /**
+     * Defines order on how virtual programs appear on the "air" with
+     * ITunerSession::scan operation.
+     *
+     * It's for default implementation purposes, may not be complete or correct.
+     */
+    friend bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs);
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALPROGRAM_H
diff --git a/broadcastradio/2.0/default/VirtualRadio.cpp b/broadcastradio/2.0/default/VirtualRadio.cpp
new file mode 100644
index 0000000..f601d41
--- /dev/null
+++ b/broadcastradio/2.0/default/VirtualRadio.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BcRadioDef.VirtualRadio"
+//#define LOG_NDEBUG 0
+
+#include "VirtualRadio.h"
+
+#include <broadcastradio-utils-2x/Utils.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+using std::lock_guard;
+using std::move;
+using std::mutex;
+using std::vector;
+using utils::make_selector_amfm;
+
+VirtualRadio gAmFmRadio(
+    "AM/FM radio mock",
+    {
+        {make_selector_amfm(94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
+        {make_selector_amfm(96500), "KOIT", "Celine Dion", "All By Myself"},
+        {make_selector_amfm(97300), "Alice@97.3", "Drops of Jupiter", "Train"},
+        {make_selector_amfm(99700), "99.7 Now!", "The Chainsmokers", "Closer"},
+        {make_selector_amfm(101300), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"},
+        {make_selector_amfm(103700), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"},
+        {make_selector_amfm(106100), "106 KMEL", "Drake", "Marvins Room"},
+    });
+
+VirtualRadio::VirtualRadio(const std::string& name, const vector<VirtualProgram>& initialList)
+    : mName(name), mPrograms(initialList) {}
+
+std::string VirtualRadio::getName() const {
+    return mName;
+}
+
+vector<VirtualProgram> VirtualRadio::getProgramList() const {
+    lock_guard<mutex> lk(mMut);
+    return mPrograms;
+}
+
+bool VirtualRadio::getProgram(const ProgramSelector& selector, VirtualProgram& programOut) const {
+    lock_guard<mutex> lk(mMut);
+    for (auto&& program : mPrograms) {
+        if (utils::tunesTo(selector, program.selector)) {
+            programOut = program;
+            return true;
+        }
+    }
+    return false;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/2.0/default/VirtualRadio.h b/broadcastradio/2.0/default/VirtualRadio.h
new file mode 100644
index 0000000..9c07816
--- /dev/null
+++ b/broadcastradio/2.0/default/VirtualRadio.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALRADIO_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALRADIO_H
+
+#include "VirtualProgram.h"
+
+#include <mutex>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+
+/**
+ * A radio frequency space mock.
+ *
+ * This represents all broadcast waves in the air for a given radio technology,
+ * not a captured station list in the radio tuner memory.
+ *
+ * It's meant to abstract out radio content from default tuner implementation.
+ */
+class VirtualRadio {
+   public:
+    VirtualRadio(const std::string& name, const std::vector<VirtualProgram>& initialList);
+
+    std::string getName() const;
+    std::vector<VirtualProgram> getProgramList() const;
+    bool getProgram(const ProgramSelector& selector, VirtualProgram& program) const;
+
+   private:
+    mutable std::mutex mMut;
+    std::string mName;
+    std::vector<VirtualProgram> mPrograms;
+};
+
+/** AM/FM virtual radio space. */
+extern VirtualRadio gAmFmRadio;
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V2_0_VIRTUALRADIO_H
diff --git a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
new file mode 100644
index 0000000..7d68b6c
--- /dev/null
+++ b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
@@ -0,0 +1,4 @@
+service broadcastradio-hal2 /vendor/bin/hw/android.hardware.broadcastradio@2.0-service
+    class hal
+    user audioserver
+    group audio
diff --git a/broadcastradio/2.0/default/resources.h b/broadcastradio/2.0/default/resources.h
new file mode 100644
index 0000000..97360dd
--- /dev/null
+++ b/broadcastradio/2.0/default/resources.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V2_0_RESOURCES_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V2_0_RESOURCES_H
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace implementation {
+namespace resources {
+
+constexpr int32_t demoPngId = 123456;
+constexpr uint8_t demoPng[] = {
+    0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44,
+    0x52, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x08, 0x02, 0x00, 0x00, 0x00, 0x25,
+    0x0b, 0xe6, 0x89, 0x00, 0x00, 0x00, 0x5d, 0x49, 0x44, 0x41, 0x54, 0x68, 0xde, 0xed, 0xd9,
+    0xc1, 0x09, 0x00, 0x30, 0x08, 0x04, 0xc1, 0x33, 0xfd, 0xf7, 0x6c, 0x6a, 0xc8, 0x23, 0x04,
+    0xc9, 0x6c, 0x01, 0xc2, 0x20, 0xbe, 0x4c, 0x86, 0x57, 0x49, 0xba, 0xfb, 0xd6, 0xf4, 0xba,
+    0x3e, 0x7f, 0x4d, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8f, 0x00, 0xbd, 0xce, 0x7f,
+    0xc0, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xb8, 0x0d, 0x32, 0xd4, 0x0c, 0x77, 0xbd,
+    0xfb, 0xc1, 0xce, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+
+}  // namespace resources
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V2_0_RESOURCES_H
diff --git a/broadcastradio/2.0/default/service.cpp b/broadcastradio/2.0/default/service.cpp
new file mode 100644
index 0000000..7e677a1
--- /dev/null
+++ b/broadcastradio/2.0/default/service.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BcRadioDef.service"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "BroadcastRadio.h"
+#include "VirtualRadio.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::broadcastradio::V2_0::implementation::BroadcastRadio;
+using android::hardware::broadcastradio::V2_0::implementation::gAmFmRadio;
+
+int main(int /* argc */, char** /* argv */) {
+    configureRpcThreadpool(4, true);
+
+    BroadcastRadio broadcastRadio(gAmFmRadio);
+    auto status = broadcastRadio.registerAsService();
+    CHECK_EQ(status, android::OK) << "Failed to register Broadcast Radio HAL implementation";
+
+    joinRpcThreadpool();
+    return 1;  // joinRpcThreadpool shouldn't exit
+}
diff --git a/broadcastradio/2.0/types.hal b/broadcastradio/2.0/types.hal
new file mode 100644
index 0000000..9fd0738
--- /dev/null
+++ b/broadcastradio/2.0/types.hal
@@ -0,0 +1,855 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.broadcastradio@2.0;
+
+/** Constants used by broadcast radio HAL. */
+enum Constants : int32_t {
+    /** Invalid identifier for IBroadcastRadio::getImage. */
+    INVALID_IMAGE = 0,
+
+    /**
+     * If the antenna is disconnected from the beginning, the
+     * onAntennaStateChange callback must be called within this time.
+     */
+    ANTENNA_DISCONNECTED_TIMEOUT_MS = 100,
+
+    LIST_COMPLETE_TIMEOUT_MS = 300000,
+};
+
+enum Result : int32_t {
+    OK,
+    UNKNOWN_ERROR,
+    INTERNAL_ERROR,
+    INVALID_ARGUMENTS,
+    INVALID_STATE,
+    NOT_SUPPORTED,
+    TIMEOUT,
+};
+
+/**
+ * Configuration flags to be used with isConfigFlagSet and setConfigFlag methods
+ * of ITunerSession.
+ */
+enum ConfigFlag : uint32_t {
+    /**
+     * Forces mono audio stream reception.
+     *
+     * Analog broadcasts can recover poor reception conditions by jointing
+     * stereo channels into one. Mainly for, but not limited to AM/FM.
+     */
+    FORCE_MONO = 1,
+
+    /**
+     * Forces the analog playback for the supporting radio technology.
+     *
+     * User may disable digital playback for FM HD Radio or hybrid FM/DAB with
+     * this option. This is purely user choice, ie. does not reflect digital-
+     * analog handover state managed from the HAL implementation side.
+     *
+     * Some radio technologies may not support this, ie. DAB.
+     */
+    FORCE_ANALOG,
+
+    /**
+     * Forces the digital playback for the supporting radio technology.
+     *
+     * User may disable digital-analog handover that happens with poor
+     * reception conditions. With digital forced, the radio will remain silent
+     * instead of switching to analog channel if it's available. This is purely
+     * user choice, it does not reflect the actual state of handover.
+     */
+    FORCE_DIGITAL,
+
+    /**
+     * RDS Alternative Frequencies.
+     *
+     * If set and the currently tuned RDS station broadcasts on multiple
+     * channels, radio tuner automatically switches to the best available
+     * alternative.
+     */
+    RDS_AF,
+
+    /**
+     * RDS region-specific program lock-down.
+     *
+     * Allows user to lock to the current region as they move into the
+     * other region.
+     */
+    RDS_REG,
+
+    /** Enables DAB-DAB hard- and implicit-linking (the same content). */
+    DAB_DAB_LINKING,
+
+    /** Enables DAB-FM hard- and implicit-linking (the same content). */
+    DAB_FM_LINKING,
+
+    /** Enables DAB-DAB soft-linking (related content). */
+    DAB_DAB_SOFT_LINKING,
+
+    /** Enables DAB-FM soft-linking (related content). */
+    DAB_FM_SOFT_LINKING,
+};
+
+/**
+ * A key-value pair for vendor-specific information to be passed as-is through
+ * Android framework to the front-end application.
+ */
+struct VendorKeyValue {
+    /**
+     * Key must start with unique vendor Java-style namespace,
+     * eg. 'com.somecompany.parameter1'.
+     */
+    string key;
+
+    /**
+     * Value must be passed through the framework without any changes.
+     * Format of this string can vary across vendors.
+     */
+    string value;
+};
+
+/**
+ * A supported or configured RDS variant.
+ *
+ * Both might be set for hardware capabilities check (with full=true when
+ * calling getAmFmRegionConfig), but only one (or none) for specific
+ * region settings.
+ */
+enum Rds : uint8_t {
+    /** Standard variant, used everywhere except North America. */
+    RDS = 1 << 0,
+
+    /** Variant used in North America. */
+    RBDS = 1 << 1,
+};
+
+/**
+ * FM de-emphasis filter supported or configured.
+ *
+ * Both might be set for hardware capabilities check (with full=true when
+ * calling getAmFmRegionConfig), but exactly one for specific region settings.
+ */
+enum Deemphasis : uint8_t {
+    D50 = 1 << 0,
+    D75 = 1 << 1,
+};
+
+/**
+ * Regional configuration for AM/FM.
+ *
+ * For hardware capabilities check (with full=true when calling
+ * getAmFmRegionConfig), HAL implementation fills entire supported range of
+ * frequencies and features.
+ *
+ * When checking current configuration, at most one bit in each bitfield
+ * can be set.
+ */
+struct AmFmRegionConfig {
+    /**
+     * All supported or configured AM/FM bands.
+     *
+     * AM/FM bands are identified by frequency value
+     * (see IdentifierType::AMFM_FREQUENCY).
+     *
+     * With typical configuration, it's expected to have two frequency ranges
+     * for capabilities check (AM and FM) and four ranges for specific region
+     * configuration (AM LW, AM MW, AM SW, FM).
+     */
+    vec<AmFmBandRange> ranges;
+
+    /** De-emphasis filter supported/configured. */
+    bitfield<Deemphasis> fmDeemphasis;
+
+    /** RDS/RBDS variant supported/configured. */
+    bitfield<Rds> fmRds;
+};
+
+/**
+ * AM/FM band range for region configuration.
+ *
+ * Defines channel grid: each possible channel is set at
+ * lowerBound + channelNumber * spacing, up to upperBound.
+ */
+struct AmFmBandRange {
+    /** The frequency of the first channel within the range. */
+    uint32_t lowerBound;
+
+    /** The frequency of the last channel within the range. */
+    uint32_t upperBound;
+
+    /** Channel grid resolution, how far apart are the channels. */
+    uint32_t spacing;
+
+    /**
+     * Spacing used when scanning for channels. It's a multiply of spacing and
+     * allows to skip some channels when scanning to make it faster.
+     *
+     * Tuner may first quickly check every n-th channel and if it detects echo
+     * from a station, it fine-tunes to find the exact frequency.
+     *
+     * It's ignored for capabilities check (with full=true when calling
+     * getAmFmRegionConfig).
+     */
+    uint32_t scanSpacing;
+};
+
+/**
+ * An entry in regional configuration for DAB.
+ *
+ * Defines a frequency table row for ensembles.
+ */
+struct DabTableEntry {
+    /**
+     * Channel name, i.e. 5A, 7B.
+     *
+     * It must match the following regular expression:
+     * /^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$/ (2-7 uppercase alphanumeric characters
+     * without spaces allowed at the beginning nor end).
+     */
+    string label;
+
+    /** Frequency, in kHz. */
+    uint32_t frequency;
+};
+
+/**
+ * Properties of a given broadcast radio module.
+ */
+struct Properties {
+    /**
+     * A company name who made the radio module. Must be a valid, registered
+     * name of the company itself.
+     *
+     * It must be opaque to the Android framework.
+     */
+    string maker;
+
+    /**
+     * A product name. Must be unique within the company.
+     *
+     * It must be opaque to the Android framework.
+     */
+    string product;
+
+    /**
+     * Version of the hardware module.
+     *
+     * It must be opaque to the Android framework.
+     */
+    string version;
+
+    /**
+     * Hardware serial number (for subscription services).
+     *
+     * It must be opaque to the Android framework.
+     */
+    string serial;
+
+    /**
+     * A list of supported IdentifierType values.
+     *
+     * If an identifier is supported by radio module, it means it can use it for
+     * tuning to ProgramSelector with either primary or secondary Identifier of
+     * a given type.
+     *
+     * Support for VENDOR identifier type does not guarantee compatibility, as
+     * other module properties (implementor, product, version) must be checked.
+     */
+    vec<uint32_t> supportedIdentifierTypes;
+
+    /**
+     * Vendor-specific information.
+     *
+     * It may be used for extra features, not supported by the platform,
+     * for example: com.me.preset-slots=6; com.me.ultra-hd-capable=false.
+     */
+    vec<VendorKeyValue> vendorInfo;
+};
+
+/**
+ * Program (channel, station) information.
+ *
+ * Carries both user-visible information (like station name) and technical
+ * details (tuning selector).
+ */
+struct ProgramInfo {
+    /**
+     * An identifier used to point at the program (primarily to tune to it).
+     */
+    ProgramSelector selector;
+
+    /**
+     * Identifier currently used for program selection.
+     *
+     * It allows to determine which technology is currently used for reception.
+     *
+     * Some program selectors contain tuning information for different radio
+     * technologies (i.e. FM RDS and DAB). For example, user may tune using
+     * a ProgramSelector with RDS_PI primary identifier, but the tuner hardware
+     * may choose to use DAB technology to make actual tuning. This identifier
+     * must reflect that.
+     *
+     * This field is optional, but must be set for currently tuned program.
+     * If it's not set, its value must be initialized to all-zeros.
+     *
+     * Only primary identifiers for a given radio technology are valid:
+     *  - AMFM_FREQUENCY for analog AM/FM;
+     *  - RDS_PI for FM RDS;
+     *  - HD_STATION_ID_EXT;
+     *  - DAB_SID_EXT;
+     *  - DRMO_SERVICE_ID;
+     *  - SXM_SERVICE_ID;
+     *  - VENDOR_*;
+     *  - more might come in next minor versions of this HAL.
+     */
+    ProgramIdentifier logicallyTunedTo;
+
+    /**
+     * Identifier currently used by hardware to physically tune to a channel.
+     *
+     * Some radio technologies broadcast the same program on multiple channels,
+     * i.e. with RDS AF the same program may be broadcasted on multiple
+     * alternative frequencies; the same DAB program may be broadcast on
+     * multiple ensembles. This identifier points to the channel to which the
+     * radio hardware is physically tuned to.
+     *
+     * This field is optional, but must be set for currently tuned program.
+     * If it's not set, its type field must be initialized to
+     * IdentifierType::INVALID.
+     *
+     * Only physical identifiers are valid:
+     *  - AMFM_FREQUENCY;
+     *  - DAB_ENSEMBLE;
+     *  - DRMO_FREQUENCY;
+     *  - SXM_CHANNEL;
+     *  - VENDOR_*;
+     *  - more might come in next minor versions of this HAL.
+     */
+    ProgramIdentifier physicallyTunedTo;
+
+    /**
+     * Primary identifiers of related contents.
+     *
+     * Some radio technologies provide pointers to other programs that carry
+     * related content (i.e. DAB soft-links). This field is a list of pointers
+     * to other programs on the program list.
+     *
+     * Please note, that these identifiers does not have to exist on the program
+     * list - i.e. DAB tuner may provide information on FM RDS alternatives
+     * despite not supporting FM RDS. If the system has multiple tuners, another
+     * one may have it on its list.
+     */
+    vec<ProgramIdentifier> relatedContent;
+
+    bitfield<ProgramInfoFlags> infoFlags;
+
+    /**
+     * Signal quality measured in 0% to 100% range to be shown in the UI.
+     *
+     * The purpose of this field is primarily informative, must not be used to
+     * determine to which frequency should it tune to.
+     */
+    uint32_t signalQuality;
+
+    /**
+     * Program metadata (station name, PTY, song title).
+     */
+    vec<Metadata> metadata;
+
+    /**
+     * Vendor-specific information.
+     *
+     * It may be used for extra features, not supported by the platform,
+     * for example: paid-service=true; bitrate=320kbps.
+     */
+    vec<VendorKeyValue> vendorInfo;
+};
+
+enum ProgramInfoFlags : uint32_t {
+    /**
+     * Set when the program is currently playing live stream.
+     * This may result in a slightly altered reception parameters,
+     * usually targetted at reduced latency.
+     */
+    LIVE = 1 << 0,
+
+    /**
+     * Radio stream is not playing, ie. due to bad reception conditions or
+     * buffering. In this state volume knob MAY be disabled to prevent user
+     * increasing volume too much.
+     */
+    MUTED = 1 << 1,
+
+    /**
+     * Station broadcasts traffic information regularly,
+     * but not necessarily right now.
+     */
+    TRAFFIC_PROGRAM = 1 << 2,
+
+    /**
+     * Station is broadcasting traffic information at the very moment.
+     */
+    TRAFFIC_ANNOUNCEMENT = 1 << 3,
+
+    /**
+     * Tuned to a program (not playing a static).
+     *
+     * It's the same condition that would stop scan() operation.
+     */
+    TUNED = 1 << 4,
+
+    /**
+     * Audio stream is MONO if this bit is not set.
+     */
+    STEREO = 1 << 5,
+};
+
+/**
+ * Type of program identifier component.
+ *
+ * Each identifier type corresponds to exactly one radio technology,
+ * i.e. DAB_ENSEMBLE is specifically for DAB.
+ *
+ * VENDOR identifier types must be opaque to the framework.
+ *
+ * The value format for each (but VENDOR_*) identifier is strictly defined
+ * to maintain interoperability between devices made by different vendors.
+ *
+ * All other values are reserved for future use.
+ * Values not matching any enumerated constant must be ignored.
+ */
+enum IdentifierType : uint32_t {
+    /**
+     * Primary/secondary identifier for vendor-specific radio technology.
+     * The value format is determined by a vendor.
+     *
+     * The vendor identifiers have limited serialization capabilities - see
+     * ProgramSelector description.
+     */
+    VENDOR_START = 1000,
+
+    /** See VENDOR_START */
+    VENDOR_END = 1999,
+
+    INVALID = 0,
+
+    /**
+     * Primary identifier for analogue (without RDS) AM/FM stations:
+     * frequency in kHz.
+     *
+     * This identifier also contains band information:
+     *  - <500kHz: AM LW;
+     *  - 500kHz - 1705kHz: AM MW;
+     *  - 1.71MHz - 30MHz: AM SW;
+     *  - >60MHz: FM.
+     */
+    AMFM_FREQUENCY,
+
+    /**
+     * 16bit primary identifier for FM RDS station.
+     */
+    RDS_PI,
+
+    /**
+     * 64bit compound primary identifier for HD Radio.
+     *
+     * Consists of (from the LSB):
+     * - 32bit: Station ID number;
+     * - 4bit: HD Radio subchannel;
+     * - 18bit: AMFM_FREQUENCY.
+     *
+     * While station ID number should be unique globally, it sometimes get
+     * abused by broadcasters (i.e. not being set at all). To ensure local
+     * uniqueness, AMFM_FREQUENCY was added here. Global uniqueness is
+     * a best-effort - see HD_STATION_NAME.
+     *
+     * HD Radio subchannel is a value in range 0-7.
+     * This index is 0-based (where 0 is MPS and 1..7 are SPS),
+     * as opposed to HD Radio standard (where it's 1-based).
+     *
+     * The remaining bits should be set to zeros when writing on the chip side
+     * and ignored when read.
+     */
+    HD_STATION_ID_EXT,
+
+    /**
+     * 64bit additional identifier for HD Radio.
+     *
+     * Due to Station ID abuse, some HD_STATION_ID_EXT identifiers may be not
+     * globally unique. To provide a best-effort solution, a short version of
+     * station name may be carried as additional identifier and may be used
+     * by the tuner hardware to double-check tuning.
+     *
+     * The name is limited to the first 8 A-Z0-9 characters (lowercase letters
+     * must be converted to uppercase). Encoded in little-endian ASCII:
+     * the first character of the name is the LSB.
+     *
+     * For example: "Abc" is encoded as 0x434241.
+     */
+    HD_STATION_NAME,
+
+    /**
+     * 28bit compound primary identifier for Digital Audio Broadcasting.
+     *
+     * Consists of (from the LSB):
+     * - 16bit: SId;
+     * - 8bit: ECC code;
+     * - 4bit: SCIdS.
+     *
+     * SCIdS (Service Component Identifier within the Service) value
+     * of 0 represents the main service, while 1 and above represents
+     * secondary services.
+     *
+     * The remaining bits should be set to zeros when writing on the chip side
+     * and ignored when read.
+     */
+    DAB_SID_EXT,
+
+    /** 16bit */
+    DAB_ENSEMBLE,
+
+    /** 12bit */
+    DAB_SCID,
+
+    /** kHz (see AMFM_FREQUENCY) */
+    DAB_FREQUENCY,
+
+    /**
+     * 24bit primary identifier for Digital Radio Mondiale.
+     */
+    DRMO_SERVICE_ID,
+
+    /** kHz (see AMFM_FREQUENCY) */
+    DRMO_FREQUENCY,
+
+    /**
+     * 32bit primary identifier for SiriusXM Satellite Radio.
+     */
+    SXM_SERVICE_ID = DRMO_FREQUENCY + 2,
+
+    /** 0-999 range */
+    SXM_CHANNEL,
+};
+
+/**
+ * A single program identifier component, i.e. frequency or channel ID.
+ */
+struct ProgramIdentifier {
+    /**
+     * Maps to IdentifierType enum. The enum may be extended in future versions
+     * of the HAL. Values out of the enum range must not be used when writing
+     * and ignored when reading.
+     */
+    uint32_t type;
+
+    /**
+     * The uint64_t value field holds the value in format described in comments
+     * for IdentifierType enum.
+     */
+    uint64_t value;
+};
+
+/**
+ * A set of identifiers necessary to tune to a given station.
+ *
+ * This can hold a combination of various identifiers, like:
+ * - AM/FM frequency,
+ * - HD Radio subchannel,
+ * - DAB service ID.
+ *
+ * The type of radio technology is determined by the primary identifier - if the
+ * primary identifier is for DAB, the program is DAB. However, a program of a
+ * specific radio technology may have additional secondary identifiers for other
+ * technologies, i.e. a satellite program may have FM fallback frequency,
+ * if a station broadcasts both via satellite and FM.
+ *
+ * The identifiers from VENDOR_START..VENDOR_END range have limited
+ * serialization capabilities: they are serialized locally, but ignored by the
+ * cloud services. If a program has primary id from vendor range, it's not
+ * synchronized with other devices at all.
+ */
+struct ProgramSelector {
+    /**
+     * Primary program identifier.
+     *
+     * This identifier uniquely identifies a station and can be used for
+     * equality check.
+     *
+     * It can hold only a subset of identifier types, one per each
+     * radio technology:
+     *  - analogue AM/FM: AMFM_FREQUENCY;
+     *  - FM RDS: RDS_PI;
+     *  - HD Radio: HD_STATION_ID_EXT;
+     *  - DAB: DAB_SID_EXT;
+     *  - Digital Radio Mondiale: DRMO_SERVICE_ID;
+     *  - SiriusXM: SXM_SERVICE_ID;
+     *  - vendor-specific: VENDOR_START..VENDOR_END.
+     *
+     * The list may change in future versions, so the implementation must obey,
+     * but not rely on it.
+     */
+    ProgramIdentifier primaryId;
+
+    /**
+     * Secondary program identifiers.
+     *
+     * These identifiers are supplementary and can speed up tuning process,
+     * but the primary ID must be sufficient (i.e. RDS PI is enough to select
+     * a station from the list after a full band scan).
+     *
+     * Two selectors with different secondary IDs, but the same primary ID are
+     * considered equal. In particular, secondary IDs vector may get updated for
+     * an entry on the program list (ie. when a better frequency for a given
+     * station is found).
+     */
+    vec<ProgramIdentifier> secondaryIds;
+};
+
+enum MetadataKey : int32_t {
+    /** RDS PS (string) */
+    RDS_PS = 1,
+
+    /** RDS PTY (uint8_t) */
+    RDS_PTY,
+
+    /** RBDS PTY (uint8_t) */
+    RBDS_PTY,
+
+    /** RDS RT (string) */
+    RDS_RT,
+
+    /** Song title (string) */
+    SONG_TITLE,
+
+    /** Artist name (string) */
+    SONG_ARTIST,
+
+    /** Album name (string) */
+    SONG_ALBUM,
+
+    /** Station icon (uint32_t, see IBroadcastRadio::getImage) */
+    STATION_ICON,
+
+    /** Album art (uint32_t, see IBroadcastRadio::getImage) */
+    ALBUM_ART,
+
+    /**
+     * Station name.
+     *
+     * This is a generic field to cover any radio technology.
+     *
+     * If the PROGRAM_NAME has the same content as DAB_*_NAME or RDS_PS,
+     * it may not be present, to preserve space - framework must repopulate
+     * it on the client side.
+     */
+    PROGRAM_NAME,
+
+    /** DAB ensemble name (string) */
+    DAB_ENSEMBLE_NAME,
+
+    /**
+     * DAB ensemble name abbreviated (string).
+     *
+     * The string must be up to 8 characters long.
+     *
+     * If the short variant is present, the long (DAB_ENSEMBLE_NAME) one must be
+     * present as well.
+     */
+    DAB_ENSEMBLE_NAME_SHORT,
+
+    /** DAB service name (string) */
+    DAB_SERVICE_NAME,
+
+    /** DAB service name abbreviated (see DAB_ENSEMBLE_NAME_SHORT) (string) */
+    DAB_SERVICE_NAME_SHORT,
+
+    /** DAB component name (string) */
+    DAB_COMPONENT_NAME,
+
+    /** DAB component name abbreviated (see DAB_ENSEMBLE_NAME_SHORT) (string) */
+    DAB_COMPONENT_NAME_SHORT,
+};
+
+/**
+ * An element of metadata vector.
+ *
+ * Contains one of the entries explained in MetadataKey.
+ *
+ * Depending on a type described in the comment for a specific key, either the
+ * intValue or stringValue field must be populated.
+ */
+struct Metadata {
+    /**
+     * Maps to MetadataKey enum. The enum may be extended in future versions
+     * of the HAL. Values out of the enum range must not be used when writing
+     * and ignored when reading.
+     */
+    uint32_t key;
+
+    int64_t intValue;
+    string stringValue;
+};
+
+/**
+ * An update packet of the program list.
+ *
+ * The order of entries in the vectors is unspecified.
+ */
+struct ProgramListChunk {
+    /**
+     * Treats all previously added entries as removed.
+     *
+     * This is meant to save binder transaction bandwidth on 'removed' vector
+     * and provide a clear empty state.
+     *
+     * If set, 'removed' vector must be empty.
+     *
+     * The client may wait with taking action on this until it received the
+     * chunk with complete flag set (to avoid part of stations temporarily
+     * disappearing from the list).
+     */
+    bool purge;
+
+    /**
+     * If false, it means there are still programs not transmitted,
+     * due for transmission in following updates.
+     *
+     * Used by UIs that wait for complete list instead of displaying
+     * programs while scanning.
+     *
+     * After the whole channel range was scanned and all discovered programs
+     * were transmitted, the last chunk must have set this flag to true.
+     * This must happen within Constants::LIST_COMPLETE_TIMEOUT_MS from the
+     * startProgramListUpdates call. If it doesn't, client may assume the tuner
+     * came into a bad state and display error message.
+     */
+    bool complete;
+
+    /**
+     * Added or modified program list entries.
+     *
+     * Two entries with the same primaryId (ProgramSelector member)
+     * are considered the same.
+     */
+    vec<ProgramInfo> modified;
+
+    /**
+     * Removed program list entries.
+     *
+     * Contains primaryId (ProgramSelector member) of a program to remove.
+     */
+    vec<ProgramIdentifier> removed;
+};
+
+/**
+ * Large-grain filter to the program list.
+ *
+ * This is meant to reduce binder transaction bandwidth, not for fine-grained
+ * filtering user might expect.
+ *
+ * The filter is designed as conjunctive normal form: the entry that passes the
+ * filter must satisfy all the clauses (members of this struct). Vector clauses
+ * are disjunctions of literals. In other words, there is AND between each
+ * high-level group and OR inside it.
+ */
+struct ProgramFilter {
+    /**
+     * List of identifier types that satisfy the filter.
+     *
+     * If the program list entry contains at least one identifier of the type
+     * listed, it satisfies this condition.
+     *
+     * Empty list means no filtering on identifier type.
+     */
+    vec<uint32_t> identifierTypes;
+
+    /**
+     * List of identifiers that satisfy the filter.
+     *
+     * If the program list entry contains at least one listed identifier,
+     * it satisfies this condition.
+     *
+     * Empty list means no filtering on identifier.
+     */
+    vec<ProgramIdentifier> identifiers;
+
+    /**
+     * Includes non-tunable entries that define tree structure on the
+     * program list (i.e. DAB ensembles).
+     */
+    bool includeCategories;
+
+    /**
+     * Disable updates on entry modifications.
+     *
+     * If true, 'modified' vector of ProgramListChunk must contain list
+     * additions only. Once the program is added to the list, it's not
+     * updated anymore.
+     */
+    bool excludeModifications;
+};
+
+/**
+ * Type of an announcement.
+ *
+ * It maps to different announcement types per each radio technology.
+ */
+enum AnnouncementType : uint8_t {
+    /** DAB alarm, RDS emergency program type (PTY 31). */
+    EMERGENCY = 1,
+
+    /** DAB warning. */
+    WARNING,
+
+    /** DAB road traffic, RDS TA, HD Radio transportation. */
+    TRAFFIC,
+
+    /** Weather. */
+    WEATHER,
+
+    /** News. */
+    NEWS,
+
+    /** DAB event, special event. */
+    EVENT,
+
+    /** DAB sport report, RDS sports. */
+    SPORT,
+
+    /** All others. */
+    MISC,
+};
+
+/**
+ * A pointer to a station broadcasting active announcement.
+ */
+struct Announcement {
+    /**
+     * Program selector to tune to the announcement.
+     */
+    ProgramSelector selector;
+
+    /** Announcement type. */
+    AnnouncementType type;
+
+    /**
+     * Vendor-specific information.
+     *
+     * It may be used for extra features, not supported by the platform,
+     * for example: com.me.hdradio.urgency=100; com.me.hdradio.certainity=50.
+     */
+    vec<VendorKeyValue> vendorInfo;
+};
diff --git a/broadcastradio/2.0/vts/OWNERS b/broadcastradio/2.0/vts/OWNERS
new file mode 100644
index 0000000..12adf57
--- /dev/null
+++ b/broadcastradio/2.0/vts/OWNERS
@@ -0,0 +1,7 @@
+# Automotive team
+egranata@google.com
+twasilczyk@google.com
+
+# VTS team
+yuexima@google.com
+yim@google.com
diff --git a/broadcastradio/2.0/vts/functional/Android.bp b/broadcastradio/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..6940bca
--- /dev/null
+++ b/broadcastradio/2.0/vts/functional/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalBroadcastradioV2_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    cppflags: [
+        "-std=c++1z",
+    ],
+    srcs: ["VtsHalBroadcastradioV2_0TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.broadcastradio@2.0",
+        "android.hardware.broadcastradio@common-utils-2x-lib",
+        "android.hardware.broadcastradio@vts-utils-lib",
+        "android.hardware.broadcastradio@vts-utils-lib",
+        "libgmock",
+    ],
+}
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
new file mode 100644
index 0000000..37095d4
--- /dev/null
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -0,0 +1,785 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BcRadio.vts"
+#define LOG_NDEBUG 0
+#define EGMOCK_VERBOSE 1
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/broadcastradio/2.0/IBroadcastRadio.h>
+#include <android/hardware/broadcastradio/2.0/ITunerCallback.h>
+#include <android/hardware/broadcastradio/2.0/ITunerSession.h>
+#include <android/hardware/broadcastradio/2.0/types.h>
+#include <broadcastradio-utils-2x/Utils.h>
+#include <broadcastradio-vts-utils/call-barrier.h>
+#include <broadcastradio-vts-utils/mock-timeout.h>
+#include <broadcastradio-vts-utils/pointer-utils.h>
+#include <cutils/bitops.h>
+#include <gmock/gmock.h>
+
+#include <chrono>
+#include <optional>
+#include <regex>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V2_0 {
+namespace vts {
+
+using namespace std::chrono_literals;
+
+using std::unordered_set;
+using std::vector;
+using testing::_;
+using testing::AnyNumber;
+using testing::ByMove;
+using testing::DoAll;
+using testing::Invoke;
+using testing::SaveArg;
+
+using broadcastradio::vts::CallBarrier;
+using broadcastradio::vts::clearAndWait;
+using utils::make_identifier;
+using utils::make_selector_amfm;
+
+namespace timeout {
+
+static constexpr auto tune = 30s;
+static constexpr auto programListScan = 5min;
+
+}  // namespace timeout
+
+static const ConfigFlag gConfigFlagValues[] = {
+    ConfigFlag::FORCE_MONO,
+    ConfigFlag::FORCE_ANALOG,
+    ConfigFlag::FORCE_DIGITAL,
+    ConfigFlag::RDS_AF,
+    ConfigFlag::RDS_REG,
+    ConfigFlag::DAB_DAB_LINKING,
+    ConfigFlag::DAB_FM_LINKING,
+    ConfigFlag::DAB_DAB_SOFT_LINKING,
+    ConfigFlag::DAB_FM_SOFT_LINKING,
+};
+
+class TunerCallbackMock : public ITunerCallback {
+   public:
+    TunerCallbackMock();
+
+    MOCK_METHOD2(onTuneFailed, Return<void>(Result, const ProgramSelector&));
+    MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChanged, Return<void>(const ProgramInfo&));
+    Return<void> onProgramListUpdated(const ProgramListChunk& chunk);
+    MOCK_METHOD1(onAntennaStateChange, Return<void>(bool connected));
+    MOCK_METHOD1(onParametersUpdated, Return<void>(const hidl_vec<VendorKeyValue>& parameters));
+
+    MOCK_TIMEOUT_METHOD0(onProgramListReady, void());
+
+    std::mutex mLock;
+    utils::ProgramInfoSet mProgramList;
+};
+
+struct AnnouncementListenerMock : public IAnnouncementListener {
+    MOCK_METHOD1(onListUpdated, Return<void>(const hidl_vec<Announcement>&));
+};
+
+class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase {
+   protected:
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+
+    bool openSession();
+    bool getAmFmRegionConfig(bool full, AmFmRegionConfig* config);
+    std::optional<utils::ProgramInfoSet> getProgramList();
+
+    sp<IBroadcastRadio> mModule;
+    Properties mProperties;
+    sp<ITunerSession> mSession;
+    sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
+};
+
+static void printSkipped(std::string msg) {
+    std::cout << "[  SKIPPED ] " << msg << std::endl;
+}
+
+MATCHER_P(InfoHasId, id,
+          std::string(negation ? "does not contain" : "contains") + " " + toString(id)) {
+    auto ids = utils::getAllIds(arg.selector, utils::getType(id));
+    return ids.end() != find(ids.begin(), ids.end(), id.value);
+}
+
+TunerCallbackMock::TunerCallbackMock() {
+    EXPECT_TIMEOUT_CALL(*this, onCurrentProgramInfoChanged, _).Times(AnyNumber());
+
+    // we expect the antenna is connected through the whole test
+    EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
+}
+
+Return<void> TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) {
+    std::lock_guard<std::mutex> lk(mLock);
+
+    updateProgramList(mProgramList, chunk);
+
+    if (chunk.complete) onProgramListReady();
+
+    return {};
+}
+
+void BroadcastRadioHalTest::SetUp() {
+    EXPECT_EQ(nullptr, mModule.get()) << "Module is already open";
+
+    // lookup HIDL service (radio module)
+    mModule = getService<IBroadcastRadio>();
+    ASSERT_NE(nullptr, mModule.get()) << "Couldn't find broadcast radio HAL implementation";
+
+    // get module properties
+    auto propResult = mModule->getProperties([&](const Properties& p) { mProperties = p; });
+    ASSERT_TRUE(propResult.isOk());
+
+    EXPECT_FALSE(mProperties.maker.empty());
+    EXPECT_FALSE(mProperties.product.empty());
+    EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
+}
+
+void BroadcastRadioHalTest::TearDown() {
+    mSession.clear();
+    mModule.clear();
+    clearAndWait(mCallback, 1s);
+}
+
+bool BroadcastRadioHalTest::openSession() {
+    EXPECT_EQ(nullptr, mSession.get()) << "Session is already open";
+
+    Result halResult = Result::UNKNOWN_ERROR;
+    auto openCb = [&](Result result, const sp<ITunerSession>& session) {
+        halResult = result;
+        if (result != Result::OK) return;
+        mSession = session;
+    };
+    auto hidlResult = mModule->openSession(mCallback, openCb);
+
+    EXPECT_TRUE(hidlResult.isOk());
+    EXPECT_EQ(Result::OK, halResult);
+    EXPECT_NE(nullptr, mSession.get());
+
+    return nullptr != mSession.get();
+}
+
+bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
+    auto halResult = Result::UNKNOWN_ERROR;
+    auto cb = [&](Result result, AmFmRegionConfig configCb) {
+        halResult = result;
+        if (config) *config = configCb;
+    };
+
+    auto hidlResult = mModule->getAmFmRegionConfig(full, cb);
+    EXPECT_TRUE(hidlResult.isOk());
+
+    if (halResult == Result::NOT_SUPPORTED) return false;
+
+    EXPECT_EQ(Result::OK, halResult);
+    return halResult == Result::OK;
+}
+
+std::optional<utils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() {
+    EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber());
+
+    auto startResult = mSession->startProgramListUpdates({});
+    if (startResult == Result::NOT_SUPPORTED) {
+        printSkipped("Program list not supported");
+        return nullopt;
+    }
+    EXPECT_EQ(Result::OK, startResult);
+    if (startResult != Result::OK) return nullopt;
+
+    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, timeout::programListScan);
+
+    auto stopResult = mSession->stopProgramListUpdates();
+    EXPECT_TRUE(stopResult.isOk());
+
+    return mCallback->mProgramList;
+}
+
+/**
+ * Test session opening.
+ *
+ * Verifies that:
+ *  - the method succeeds on a first and subsequent calls;
+ *  - the method succeeds when called for the second time without
+ *    closing previous session.
+ */
+TEST_F(BroadcastRadioHalTest, OpenSession) {
+    // simply open session for the first time
+    ASSERT_TRUE(openSession());
+
+    // drop (without explicit close) and re-open the session
+    mSession.clear();
+    ASSERT_TRUE(openSession());
+
+    // open the second session (the first one should be forcibly closed)
+    auto secondSession = mSession;
+    mSession.clear();
+    ASSERT_TRUE(openSession());
+}
+
+static bool isValidAmFmFreq(uint64_t freq) {
+    auto id = utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq);
+    return utils::isValid(id);
+}
+
+static void validateRange(const AmFmBandRange& range) {
+    EXPECT_TRUE(isValidAmFmFreq(range.lowerBound));
+    EXPECT_TRUE(isValidAmFmFreq(range.upperBound));
+    EXPECT_LT(range.lowerBound, range.upperBound);
+    EXPECT_GT(range.spacing, 0u);
+    EXPECT_EQ(0u, (range.upperBound - range.lowerBound) % range.spacing);
+}
+
+static bool supportsFM(const AmFmRegionConfig& config) {
+    for (auto&& range : config.ranges) {
+        if (utils::getBand(range.lowerBound) == utils::FrequencyBand::FM) return true;
+    }
+    return false;
+}
+
+/**
+ * Test fetching AM/FM regional configuration.
+ *
+ * Verifies that:
+ *  - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
+ *  - there is at least one AM/FM band configured;
+ *  - FM Deemphasis and RDS are correctly configured for FM-capable radio;
+ *  - all channel grids (frequency ranges and spacings) are valid;
+ *  - scan spacing is a multiply of manual spacing value.
+ */
+TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfig) {
+    AmFmRegionConfig config;
+    bool supported = getAmFmRegionConfig(false, &config);
+    if (!supported) {
+        printSkipped("AM/FM not supported");
+        return;
+    }
+
+    EXPECT_GT(config.ranges.size(), 0u);
+    EXPECT_LE(popcountll(config.fmDeemphasis), 1);
+    EXPECT_LE(popcountll(config.fmRds), 1);
+
+    for (auto&& range : config.ranges) {
+        validateRange(range);
+        EXPECT_EQ(0u, range.scanSpacing % range.spacing);
+        EXPECT_GE(range.scanSpacing, range.spacing);
+    }
+
+    if (supportsFM(config)) {
+        EXPECT_EQ(popcountll(config.fmDeemphasis), 1);
+    }
+}
+
+/**
+ * Test fetching AM/FM regional capabilities.
+ *
+ * Verifies that:
+ *  - AM/FM regional capabilities are either available or not supported at all by the hardware;
+ *  - there is at least one AM/FM range supported;
+ *  - there is at least one de-emphasis filter mode supported for FM-capable radio;
+ *  - all channel grids (frequency ranges and spacings) are valid;
+ *  - scan spacing is not set.
+ */
+TEST_F(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilities) {
+    AmFmRegionConfig config;
+    bool supported = getAmFmRegionConfig(true, &config);
+    if (!supported) {
+        printSkipped("AM/FM not supported");
+        return;
+    }
+
+    EXPECT_GT(config.ranges.size(), 0u);
+
+    for (auto&& range : config.ranges) {
+        validateRange(range);
+        EXPECT_EQ(0u, range.scanSpacing);
+    }
+
+    if (supportsFM(config)) {
+        EXPECT_GE(popcountll(config.fmDeemphasis), 1);
+    }
+}
+
+/**
+ * Test fetching DAB regional configuration.
+ *
+ * Verifies that:
+ *  - DAB regional configuration is either set at startup or not supported at all by the hardware;
+ *  - all channel labels match correct format;
+ *  - all channel frequencies are in correct range.
+ */
+TEST_F(BroadcastRadioHalTest, GetDabRegionConfig) {
+    Result halResult;
+    hidl_vec<DabTableEntry> config;
+    auto cb = [&](Result result, hidl_vec<DabTableEntry> configCb) {
+        halResult = result;
+        config = configCb;
+    };
+    auto hidlResult = mModule->getDabRegionConfig(cb);
+    ASSERT_TRUE(hidlResult.isOk());
+
+    if (halResult == Result::NOT_SUPPORTED) {
+        printSkipped("DAB not supported");
+        return;
+    }
+    ASSERT_EQ(Result::OK, halResult);
+
+    std::regex re("^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$");
+    // double-check correctness of the test
+    ASSERT_TRUE(std::regex_match("5A", re));
+    ASSERT_FALSE(std::regex_match("5a", re));
+    ASSERT_FALSE(std::regex_match("1234ABCD", re));
+    ASSERT_TRUE(std::regex_match("CN 12D", re));
+    ASSERT_FALSE(std::regex_match(" 5A", re));
+
+    for (auto&& entry : config) {
+        EXPECT_TRUE(std::regex_match(std::string(entry.label), re));
+
+        auto id = utils::make_identifier(IdentifierType::DAB_FREQUENCY, entry.frequency);
+        EXPECT_TRUE(utils::isValid(id));
+    }
+}
+
+/**
+ * Test tuning with FM selector.
+ *
+ * Verifies that:
+ *  - if AM/FM selector is not supported, the method returns NOT_SUPPORTED;
+ *  - if it is supported, the method succeeds;
+ *  - after a successful tune call, onCurrentProgramInfoChanged callback is
+ *    invoked carrying a proper selector;
+ *  - program changes exactly to what was requested.
+ */
+TEST_F(BroadcastRadioHalTest, FmTune) {
+    ASSERT_TRUE(openSession());
+
+    uint64_t freq = 100100;  // 100.1 FM
+    auto sel = make_selector_amfm(freq);
+
+    /* TODO(b/69958777): there is a race condition between tune() and onCurrentProgramInfoChanged
+     * callback setting infoCb, because egmock cannot distinguish calls with different matchers
+     * (there is one here and one in callback constructor).
+     *
+     * This sleep workaround will fix default implementation, but the real HW tests will still be
+     * flaky. We probably need to implement egmock alternative based on actions.
+     */
+    std::this_thread::sleep_for(100ms);
+
+    // try tuning
+    ProgramInfo infoCb = {};
+    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged,
+                        InfoHasId(utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq)))
+        .Times(AnyNumber())
+        .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void()))));
+    auto result = mSession->tune(sel);
+
+    // expect a failure if it's not supported
+    if (!utils::isSupported(mProperties, sel)) {
+        EXPECT_EQ(Result::NOT_SUPPORTED, result);
+        return;
+    }
+
+    // expect a callback if it succeeds
+    EXPECT_EQ(Result::OK, result);
+    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
+
+    ALOGD("current program info: %s", toString(infoCb).c_str());
+
+    // it should tune exactly to what was requested
+    auto freqs = utils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY);
+    EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq));
+}
+
+/**
+ * Test tuning with invalid selectors.
+ *
+ * Verifies that:
+ *  - if the selector is not supported, it's ignored;
+ *  - if it is supported, an invalid value results with INVALID_ARGUMENTS;
+ */
+TEST_F(BroadcastRadioHalTest, TuneFailsWithInvalid) {
+    ASSERT_TRUE(openSession());
+
+    vector<ProgramIdentifier> invalid = {
+        make_identifier(IdentifierType::AMFM_FREQUENCY, 0),
+        make_identifier(IdentifierType::RDS_PI, 0x10000),
+        make_identifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),
+        make_identifier(IdentifierType::DAB_SID_EXT, 0),
+        make_identifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),
+        make_identifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),
+    };
+
+    for (auto&& id : invalid) {
+        ProgramSelector sel{id, {}};
+
+        auto result = mSession->tune(sel);
+
+        if (utils::isSupported(mProperties, sel)) {
+            EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
+        } else {
+            EXPECT_EQ(Result::NOT_SUPPORTED, result);
+        }
+    }
+}
+
+/**
+ * Test tuning with empty program selector.
+ *
+ * Verifies that:
+ *  - tune fails with NOT_SUPPORTED when program selector is not initialized.
+ */
+TEST_F(BroadcastRadioHalTest, TuneFailsWithEmpty) {
+    ASSERT_TRUE(openSession());
+
+    // Program type is 1-based, so 0 will always be invalid.
+    ProgramSelector sel = {};
+    auto result = mSession->tune(sel);
+    ASSERT_EQ(Result::NOT_SUPPORTED, result);
+}
+
+/**
+ * Test scanning to next/prev station.
+ *
+ * Verifies that:
+ *  - the method succeeds;
+ *  - the program info is changed within timeout::tune;
+ *  - works both directions and with or without skipping sub-channel.
+ */
+TEST_F(BroadcastRadioHalTest, Scan) {
+    ASSERT_TRUE(openSession());
+
+    // TODO(b/69958777): see FmTune workaround
+    std::this_thread::sleep_for(100ms);
+
+    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _);
+    auto result = mSession->scan(true /* up */, true /* skip subchannel */);
+    EXPECT_EQ(Result::OK, result);
+    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
+
+    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _);
+    result = mSession->scan(false /* down */, false /* don't skip subchannel */);
+    EXPECT_EQ(Result::OK, result);
+    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
+}
+
+/**
+ * Test step operation.
+ *
+ * Verifies that:
+ *  - the method succeeds or returns NOT_SUPPORTED;
+ *  - the program info is changed within timeout::tune if the method succeeded;
+ *  - works both directions.
+ */
+TEST_F(BroadcastRadioHalTest, Step) {
+    ASSERT_TRUE(openSession());
+
+    // TODO(b/69958777): see FmTune workaround
+    std::this_thread::sleep_for(100ms);
+
+    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _).Times(AnyNumber());
+    auto result = mSession->step(true /* up */);
+    if (result == Result::NOT_SUPPORTED) {
+        printSkipped("step not supported");
+        return;
+    }
+    EXPECT_EQ(Result::OK, result);
+    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
+
+    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChanged, _);
+    result = mSession->step(false /* down */);
+    EXPECT_EQ(Result::OK, result);
+    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChanged, timeout::tune);
+}
+
+/**
+ * Test tune cancellation.
+ *
+ * Verifies that:
+ *  - the method does not crash after being invoked multiple times.
+ */
+TEST_F(BroadcastRadioHalTest, Cancel) {
+    ASSERT_TRUE(openSession());
+
+    for (int i = 0; i < 10; i++) {
+        auto scanResult = mSession->scan(true /* up */, true /* skip subchannel */);
+        ASSERT_EQ(Result::OK, scanResult);
+
+        auto cancelResult = mSession->cancel();
+        ASSERT_TRUE(cancelResult.isOk());
+    }
+}
+
+/**
+ * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
+ *
+ * Verifies that:
+ *  - callback is called for empty parameters set.
+ */
+TEST_F(BroadcastRadioHalTest, NoParameters) {
+    ASSERT_TRUE(openSession());
+
+    hidl_vec<VendorKeyValue> halResults = {};
+    bool wasCalled = false;
+    auto cb = [&](hidl_vec<VendorKeyValue> results) {
+        wasCalled = true;
+        halResults = results;
+    };
+
+    auto hidlResult = mSession->setParameters({}, cb);
+    ASSERT_TRUE(hidlResult.isOk());
+    ASSERT_TRUE(wasCalled);
+    ASSERT_EQ(0u, halResults.size());
+
+    wasCalled = false;
+    hidlResult = mSession->getParameters({}, cb);
+    ASSERT_TRUE(hidlResult.isOk());
+    ASSERT_TRUE(wasCalled);
+    ASSERT_EQ(0u, halResults.size());
+}
+
+/**
+ * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
+ *
+ * Verifies that:
+ *  - unknown parameters are ignored;
+ *  - callback is called also for empty results set.
+ */
+TEST_F(BroadcastRadioHalTest, UnknownParameters) {
+    ASSERT_TRUE(openSession());
+
+    hidl_vec<VendorKeyValue> halResults = {};
+    bool wasCalled = false;
+    auto cb = [&](hidl_vec<VendorKeyValue> results) {
+        wasCalled = true;
+        halResults = results;
+    };
+
+    auto hidlResult = mSession->setParameters({{"com.google.unknown", "dummy"}}, cb);
+    ASSERT_TRUE(hidlResult.isOk());
+    ASSERT_TRUE(wasCalled);
+    ASSERT_EQ(0u, halResults.size());
+
+    wasCalled = false;
+    hidlResult = mSession->getParameters({{"com.google.unknown*", "dummy"}}, cb);
+    ASSERT_TRUE(hidlResult.isOk());
+    ASSERT_TRUE(wasCalled);
+    ASSERT_EQ(0u, halResults.size());
+}
+
+/**
+ * Test session closing.
+ *
+ * Verifies that:
+ *  - the method does not crash after being invoked multiple times.
+ */
+TEST_F(BroadcastRadioHalTest, Close) {
+    ASSERT_TRUE(openSession());
+
+    for (int i = 0; i < 10; i++) {
+        auto cancelResult = mSession->close();
+        ASSERT_TRUE(cancelResult.isOk());
+    }
+}
+
+/**
+ * Test geting image of invalid ID.
+ *
+ * Verifies that:
+ * - getImage call handles argument 0 gracefully.
+ */
+TEST_F(BroadcastRadioHalTest, GetNoImage) {
+    size_t len = 0;
+    auto result = mModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
+
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(0u, len);
+}
+
+/**
+ * Test getting config flags.
+ *
+ * Verifies that:
+ * - isConfigFlagSet either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
+ * - call success or failure is consistent with setConfigFlag.
+ */
+TEST_F(BroadcastRadioHalTest, FetchConfigFlags) {
+    ASSERT_TRUE(openSession());
+
+    for (auto flag : gConfigFlagValues) {
+        auto halResult = Result::UNKNOWN_ERROR;
+        auto cb = [&](Result result, bool) { halResult = result; };
+        auto hidlResult = mSession->isConfigFlagSet(flag, cb);
+        EXPECT_TRUE(hidlResult.isOk());
+
+        if (halResult != Result::NOT_SUPPORTED && halResult != Result::INVALID_STATE) {
+            ASSERT_EQ(Result::OK, halResult);
+        }
+
+        // set must fail or succeed the same way as get
+        auto setResult = mSession->setConfigFlag(flag, false);
+        EXPECT_EQ(halResult, setResult);
+        setResult = mSession->setConfigFlag(flag, true);
+        EXPECT_EQ(halResult, setResult);
+    }
+}
+
+/**
+ * Test setting config flags.
+ *
+ * Verifies that:
+ * - setConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
+ * - isConfigFlagSet reflects the state requested immediately after the set call.
+ */
+TEST_F(BroadcastRadioHalTest, SetConfigFlags) {
+    ASSERT_TRUE(openSession());
+
+    auto get = [&](ConfigFlag flag) {
+        auto halResult = Result::UNKNOWN_ERROR;
+        bool gotValue = false;
+        auto cb = [&](Result result, bool value) {
+            halResult = result;
+            gotValue = value;
+        };
+        auto hidlResult = mSession->isConfigFlagSet(flag, cb);
+        EXPECT_TRUE(hidlResult.isOk());
+        EXPECT_EQ(Result::OK, halResult);
+        return gotValue;
+    };
+
+    for (auto flag : gConfigFlagValues) {
+        auto result = mSession->setConfigFlag(flag, false);
+        if (result == Result::NOT_SUPPORTED || result == Result::INVALID_STATE) {
+            // setting to true must result in the same error as false
+            auto secondResult = mSession->setConfigFlag(flag, true);
+            EXPECT_EQ(result, secondResult);
+            continue;
+        }
+        ASSERT_EQ(Result::OK, result);
+
+        // verify false is set
+        auto value = get(flag);
+        EXPECT_FALSE(value);
+
+        // try setting true this time
+        result = mSession->setConfigFlag(flag, true);
+        ASSERT_EQ(Result::OK, result);
+        value = get(flag);
+        EXPECT_TRUE(value);
+
+        // false again
+        result = mSession->setConfigFlag(flag, false);
+        ASSERT_EQ(Result::OK, result);
+        value = get(flag);
+        EXPECT_FALSE(value);
+    }
+}
+
+/**
+ * Test getting program list.
+ *
+ * Verifies that:
+ * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
+ * - the complete list is fetched within timeout::programListScan;
+ * - stopProgramListUpdates does not crash.
+ */
+TEST_F(BroadcastRadioHalTest, GetProgramList) {
+    ASSERT_TRUE(openSession());
+
+    getProgramList();
+}
+
+/**
+ * Test HD_STATION_NAME correctness.
+ *
+ * Verifies that if a program on the list contains HD_STATION_NAME identifier:
+ *  - the program provides station name in its metadata;
+ *  - the identifier matches the name;
+ *  - there is only one identifier of that type.
+ */
+TEST_F(BroadcastRadioHalTest, HdRadioStationNameId) {
+    ASSERT_TRUE(openSession());
+
+    auto list = getProgramList();
+    if (!list) return;
+
+    for (auto&& program : *list) {
+        auto nameIds = utils::getAllIds(program.selector, IdentifierType::HD_STATION_NAME);
+        EXPECT_LE(nameIds.size(), 1u);
+        if (nameIds.size() == 0) continue;
+
+        auto name = utils::getMetadataString(program, MetadataKey::PROGRAM_NAME);
+        if (!name) name = utils::getMetadataString(program, MetadataKey::RDS_PS);
+        ASSERT_TRUE(name.has_value());
+
+        auto expectedId = utils::make_hdradio_station_name(*name);
+        EXPECT_EQ(expectedId.value, nameIds[0]);
+    }
+}
+
+/**
+ * Test announcement listener registration.
+ *
+ * Verifies that:
+ *  - registerAnnouncementListener either succeeds or returns NOT_SUPPORTED;
+ *  - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
+ *  - closing handle does not crash.
+ */
+TEST_F(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
+    sp<AnnouncementListenerMock> listener = new AnnouncementListenerMock();
+
+    Result halResult = Result::UNKNOWN_ERROR;
+    sp<ICloseHandle> closeHandle = nullptr;
+    auto cb = [&](Result result, const sp<ICloseHandle>& closeHandle_) {
+        halResult = result;
+        closeHandle = closeHandle_;
+    };
+
+    auto hidlResult =
+        mModule->registerAnnouncementListener({AnnouncementType::EMERGENCY}, listener, cb);
+    ASSERT_TRUE(hidlResult.isOk());
+
+    if (halResult == Result::NOT_SUPPORTED) {
+        ASSERT_EQ(nullptr, closeHandle.get());
+        printSkipped("Announcements not supported");
+        return;
+    }
+
+    ASSERT_EQ(Result::OK, halResult);
+    ASSERT_NE(nullptr, closeHandle.get());
+
+    closeHandle->close();
+}
+
+// TODO(b/70939328): test ProgramInfo's currentlyTunedId and
+// currentlyTunedChannel once the program list is implemented.
+
+}  // namespace vts
+}  // namespace V2_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/broadcastradio/common/OWNERS b/broadcastradio/common/OWNERS
new file mode 100644
index 0000000..136b607
--- /dev/null
+++ b/broadcastradio/common/OWNERS
@@ -0,0 +1,3 @@
+# Automotive team
+egranata@google.com
+twasilczyk@google.com
diff --git a/broadcastradio/common/tests/Android.bp b/broadcastradio/common/tests/Android.bp
new file mode 100644
index 0000000..f6a3b6f
--- /dev/null
+++ b/broadcastradio/common/tests/Android.bp
@@ -0,0 +1,76 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "android.hardware.broadcastradio@common-utils-xx-tests",
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    cppflags: [
+        "-std=c++1z",
+    ],
+    srcs: [
+        "CommonXX_test.cpp",
+    ],
+    static_libs: [
+        "android.hardware.broadcastradio@common-utils-1x-lib",
+        "android.hardware.broadcastradio@common-utils-2x-lib",
+    ],
+    shared_libs: [
+        "android.hardware.broadcastradio@1.2",
+        "android.hardware.broadcastradio@2.0",
+    ],
+}
+
+cc_test {
+    name: "android.hardware.broadcastradio@common-utils-2x-tests",
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    cppflags: [
+        "-std=c++1z",
+    ],
+    srcs: [
+        "IdentifierIterator_test.cpp",
+        "ProgramIdentifier_test.cpp",
+    ],
+    static_libs: [
+        "android.hardware.broadcastradio@common-utils-2x-lib",
+    ],
+    shared_libs: [
+        "android.hardware.broadcastradio@2.0",
+    ],
+}
+
+cc_test {
+    name: "android.hardware.broadcastradio@common-utils-tests",
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "WorkerThread_test.cpp",
+    ],
+    static_libs: ["android.hardware.broadcastradio@common-utils-lib"],
+}
diff --git a/broadcastradio/common/tests/CommonXX_test.cpp b/broadcastradio/common/tests/CommonXX_test.cpp
new file mode 100644
index 0000000..d19204e
--- /dev/null
+++ b/broadcastradio/common/tests/CommonXX_test.cpp
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <broadcastradio-utils-1x/Utils.h>
+#include <broadcastradio-utils-2x/Utils.h>
diff --git a/broadcastradio/common/tests/IdentifierIterator_test.cpp b/broadcastradio/common/tests/IdentifierIterator_test.cpp
new file mode 100644
index 0000000..5bf222b
--- /dev/null
+++ b/broadcastradio/common/tests/IdentifierIterator_test.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <broadcastradio-utils-2x/Utils.h>
+#include <gtest/gtest.h>
+
+namespace {
+
+namespace V2_0 = android::hardware::broadcastradio::V2_0;
+namespace utils = android::hardware::broadcastradio::utils;
+
+using V2_0::IdentifierType;
+using V2_0::ProgramSelector;
+
+TEST(IdentifierIteratorTest, singleSecondary) {
+    // clang-format off
+    V2_0::ProgramSelector sel {
+        utils::make_identifier(IdentifierType::RDS_PI, 0xBEEF),
+        {utils::make_identifier(IdentifierType::AMFM_FREQUENCY, 100100)}
+    };
+    // clang-format on
+
+    auto it = utils::begin(sel);
+    auto end = utils::end(sel);
+
+    ASSERT_NE(end, it);
+    EXPECT_EQ(sel.primaryId, *it);
+    ASSERT_NE(end, ++it);
+    EXPECT_EQ(sel.secondaryIds[0], *it);
+    ASSERT_EQ(end, ++it);
+}
+
+TEST(IdentifierIteratorTest, empty) {
+    V2_0::ProgramSelector sel{};
+
+    auto it = utils::begin(sel);
+    auto end = utils::end(sel);
+
+    ASSERT_NE(end, it++);  // primary id is always present
+    ASSERT_EQ(end, it);
+}
+
+TEST(IdentifierIteratorTest, twoSelectors) {
+    V2_0::ProgramSelector sel1{};
+    V2_0::ProgramSelector sel2{};
+
+    auto it1 = utils::begin(sel1);
+    auto it2 = utils::begin(sel2);
+
+    EXPECT_NE(it1, it2);
+}
+
+TEST(IdentifierIteratorTest, increments) {
+    V2_0::ProgramSelector sel{{}, {{}, {}}};
+
+    auto it = utils::begin(sel);
+    auto end = utils::end(sel);
+    auto pre = it;
+    auto post = it;
+
+    EXPECT_NE(++pre, post++);
+    EXPECT_EQ(pre, post);
+    EXPECT_EQ(pre, it + 1);
+    ASSERT_NE(end, pre);
+}
+
+TEST(IdentifierIteratorTest, findType) {
+    using namespace std::placeholders;
+
+    uint64_t rds_pi1 = 0xDEAD;
+    uint64_t rds_pi2 = 0xBEEF;
+    uint64_t freq1 = 100100;
+    uint64_t freq2 = 107900;
+
+    // clang-format off
+    V2_0::ProgramSelector sel {
+        utils::make_identifier(IdentifierType::RDS_PI, rds_pi1),
+        {
+            utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq1),
+            utils::make_identifier(IdentifierType::RDS_PI, rds_pi2),
+            utils::make_identifier(IdentifierType::AMFM_FREQUENCY, freq2),
+        }
+    };
+    // clang-format on
+
+    auto typeEquals = [](const V2_0::ProgramIdentifier& id, V2_0::IdentifierType type) {
+        return utils::getType(id) == type;
+    };
+    auto isRdsPi = std::bind(typeEquals, _1, IdentifierType::RDS_PI);
+    auto isFreq = std::bind(typeEquals, _1, IdentifierType::AMFM_FREQUENCY);
+
+    auto end = utils::end(sel);
+    auto it = std::find_if(utils::begin(sel), end, isRdsPi);
+    ASSERT_NE(end, it);
+    EXPECT_EQ(rds_pi1, it->value);
+
+    it = std::find_if(it + 1, end, isRdsPi);
+    ASSERT_NE(end, it);
+    EXPECT_EQ(rds_pi2, it->value);
+
+    it = std::find_if(utils::begin(sel), end, isFreq);
+    ASSERT_NE(end, it);
+    EXPECT_EQ(freq1, it->value);
+
+    it = std::find_if(++it, end, isFreq);
+    ASSERT_NE(end, it);
+    EXPECT_EQ(freq2, it->value);
+}
+
+}  // anonymous namespace
diff --git a/broadcastradio/common/tests/ProgramIdentifier_test.cpp b/broadcastradio/common/tests/ProgramIdentifier_test.cpp
new file mode 100644
index 0000000..51ad014
--- /dev/null
+++ b/broadcastradio/common/tests/ProgramIdentifier_test.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <broadcastradio-utils-2x/Utils.h>
+#include <gtest/gtest.h>
+
+#include <optional>
+
+namespace {
+
+namespace utils = android::hardware::broadcastradio::utils;
+
+TEST(ProgramIdentifierTest, hdRadioStationName) {
+    auto verify = [](std::string name, uint64_t nameId) {
+        auto id = utils::make_hdradio_station_name(name);
+        EXPECT_EQ(nameId, id.value) << "Failed to convert '" << name << "'";
+    };
+
+    verify("", 0);
+    verify("Abc", 0x434241);
+    verify("Some Station 1", 0x54415453454d4f53);
+    verify("Station1", 0x314e4f4954415453);
+    verify("!@#$%^&*()_+", 0);
+    verify("-=[]{};':\"0", 0x30);
+}
+
+}  // anonymous namespace
diff --git a/broadcastradio/1.1/tests/WorkerThread_test.cpp b/broadcastradio/common/tests/WorkerThread_test.cpp
similarity index 100%
rename from broadcastradio/1.1/tests/WorkerThread_test.cpp
rename to broadcastradio/common/tests/WorkerThread_test.cpp
diff --git a/broadcastradio/common/utils/Android.bp b/broadcastradio/common/utils/Android.bp
new file mode 100644
index 0000000..33ba7da
--- /dev/null
+++ b/broadcastradio/common/utils/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.broadcastradio@common-utils-lib",
+    vendor_available: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "WorkerThread.cpp",
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/broadcastradio/1.1/utils/WorkerThread.cpp b/broadcastradio/common/utils/WorkerThread.cpp
similarity index 100%
rename from broadcastradio/1.1/utils/WorkerThread.cpp
rename to broadcastradio/common/utils/WorkerThread.cpp
diff --git a/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h b/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
new file mode 100644
index 0000000..62bede6
--- /dev/null
+++ b/broadcastradio/common/utils/include/broadcastradio-utils/WorkerThread.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_COMMON_WORKERTHREAD_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_COMMON_WORKERTHREAD_H
+
+#include <chrono>
+#include <queue>
+#include <thread>
+
+namespace android {
+
+class WorkerThread {
+   public:
+    WorkerThread();
+    virtual ~WorkerThread();
+
+    void schedule(std::function<void()> task, std::chrono::milliseconds delay);
+    void cancelAll();
+
+   private:
+    struct Task {
+        std::chrono::time_point<std::chrono::steady_clock> when;
+        std::function<void()> what;
+    };
+    friend bool operator<(const Task& lhs, const Task& rhs);
+
+    std::atomic<bool> mIsTerminating;
+    std::mutex mMut;
+    std::condition_variable mCond;
+    std::thread mThread;
+    std::priority_queue<Task> mTasks;
+
+    void threadLoop();
+};
+
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_COMMON_WORKERTHREAD_H
diff --git a/broadcastradio/common/utils1x/Android.bp b/broadcastradio/common/utils1x/Android.bp
new file mode 100644
index 0000000..127c15a
--- /dev/null
+++ b/broadcastradio/common/utils1x/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.broadcastradio@common-utils-1x-lib",
+    vendor_available: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "Utils.cpp",
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "android.hardware.broadcastradio@1.2",
+    ],
+}
diff --git a/broadcastradio/common/utils1x/Utils.cpp b/broadcastradio/common/utils1x/Utils.cpp
new file mode 100644
index 0000000..7a59d6a
--- /dev/null
+++ b/broadcastradio/common/utils1x/Utils.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BroadcastRadioDefault.utils"
+//#define LOG_NDEBUG 0
+
+#include <broadcastradio-utils-1x/Utils.h>
+
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace utils {
+
+using V1_0::Band;
+using V1_1::ProgramIdentifier;
+using V1_1::ProgramSelector;
+using V1_1::ProgramType;
+using V1_2::IdentifierType;
+
+static bool isCompatibleProgramType(const uint32_t ia, const uint32_t ib) {
+    auto a = static_cast<ProgramType>(ia);
+    auto b = static_cast<ProgramType>(ib);
+
+    if (a == b) return true;
+    if (a == ProgramType::AM && b == ProgramType::AM_HD) return true;
+    if (a == ProgramType::AM_HD && b == ProgramType::AM) return true;
+    if (a == ProgramType::FM && b == ProgramType::FM_HD) return true;
+    if (a == ProgramType::FM_HD && b == ProgramType::FM) return true;
+    return false;
+}
+
+static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
+                       const IdentifierType type) {
+    return hasId(a, type) && hasId(b, type);
+}
+
+static bool anyHaveId(const ProgramSelector& a, const ProgramSelector& b,
+                      const IdentifierType type) {
+    return hasId(a, type) || hasId(b, type);
+}
+
+static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
+                         const IdentifierType type) {
+    if (!bothHaveId(a, b, type)) return false;
+    /* We should check all Ids of a given type (ie. other AF),
+     * but it doesn't matter for default implementation.
+     */
+    return getId(a, type) == getId(b, type);
+}
+
+bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
+    if (!isCompatibleProgramType(a.programType, b.programType)) return false;
+
+    auto type = getType(a);
+
+    switch (type) {
+        case ProgramType::AM:
+        case ProgramType::AM_HD:
+        case ProgramType::FM:
+        case ProgramType::FM_HD:
+            if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
+
+            // if HD Radio subchannel is specified, it must match
+            if (anyHaveId(a, b, IdentifierType::HD_SUBCHANNEL)) {
+                // missing subchannel (analog) is an equivalent of first subchannel (MPS)
+                auto aCh = getId(a, IdentifierType::HD_SUBCHANNEL, 0);
+                auto bCh = getId(b, IdentifierType::HD_SUBCHANNEL, 0);
+                if (aCh != bCh) return false;
+            }
+
+            if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
+
+            return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
+        case ProgramType::DAB:
+            return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
+        case ProgramType::DRMO:
+            return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
+        case ProgramType::SXM:
+            if (anyHaveId(a, b, IdentifierType::SXM_SERVICE_ID)) {
+                return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
+            }
+            return haveEqualIds(a, b, IdentifierType::SXM_CHANNEL);
+        default:  // includes all vendor types
+            ALOGW("Unsupported program type: %s", toString(type).c_str());
+            return false;
+    }
+}
+
+ProgramType getType(const ProgramSelector& sel) {
+    return static_cast<ProgramType>(sel.programType);
+}
+
+bool isAmFm(const ProgramType type) {
+    switch (type) {
+        case ProgramType::AM:
+        case ProgramType::FM:
+        case ProgramType::AM_HD:
+        case ProgramType::FM_HD:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool isAm(const Band band) {
+    return band == Band::AM || band == Band::AM_HD;
+}
+
+bool isFm(const Band band) {
+    return band == Band::FM || band == Band::FM_HD;
+}
+
+static bool maybeGetId(const ProgramSelector& sel, const IdentifierType type, uint64_t* val) {
+    auto itype = static_cast<uint32_t>(type);
+    auto itypeAlt = itype;
+    if (type == IdentifierType::DAB_SIDECC) {
+        itypeAlt = static_cast<uint32_t>(IdentifierType::DAB_SID_EXT);
+    }
+    if (type == IdentifierType::DAB_SID_EXT) {
+        itypeAlt = static_cast<uint32_t>(IdentifierType::DAB_SIDECC);
+    }
+
+    if (sel.primaryId.type == itype || sel.primaryId.type == itypeAlt) {
+        if (val) *val = sel.primaryId.value;
+        return true;
+    }
+
+    // not optimal, but we don't care in default impl
+    bool gotAlt = false;
+    for (auto&& id : sel.secondaryIds) {
+        if (id.type == itype) {
+            if (val) *val = id.value;
+            return true;
+        }
+        // alternative identifier is a backup, we prefer original value
+        if (id.type == itypeAlt) {
+            if (val) *val = id.value;
+            gotAlt = true;
+            continue;
+        }
+    }
+
+    return gotAlt;
+}
+
+bool hasId(const ProgramSelector& sel, const IdentifierType type) {
+    return maybeGetId(sel, type, nullptr);
+}
+
+uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
+    uint64_t val;
+
+    if (maybeGetId(sel, type, &val)) {
+        return val;
+    }
+
+    ALOGW("Identifier %s not found", toString(type).c_str());
+    return 0;
+}
+
+uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
+    if (!hasId(sel, type)) return defval;
+    return getId(sel, type);
+}
+
+ProgramSelector make_selector(Band band, uint32_t channel, uint32_t subChannel) {
+    ProgramSelector sel = {};
+
+    ALOGW_IF((subChannel > 0) && (band == Band::AM || band == Band::FM),
+             "got subChannel for non-HD AM/FM");
+
+    // we can't use ProgramType::AM_HD or FM_HD, because we don't know HD station ID
+    ProgramType type;
+    if (isAm(band)) {
+        type = ProgramType::AM;
+    } else if (isFm(band)) {
+        type = ProgramType::FM;
+    } else {
+        LOG_ALWAYS_FATAL("Unsupported band: %s", toString(band).c_str());
+    }
+
+    sel.programType = static_cast<uint32_t>(type);
+    sel.primaryId.type = static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY);
+    sel.primaryId.value = channel;
+    if (subChannel > 0) {
+        /* stating sub channel for AM/FM channel does not give any guarantees,
+         * but we can't do much more without HD station ID
+         *
+         * The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based.
+         */
+        sel.secondaryIds = hidl_vec<ProgramIdentifier>{
+            {static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL), subChannel - 1},
+        };
+    }
+
+    return sel;
+}
+
+bool getLegacyChannel(const ProgramSelector& sel, uint32_t* channelOut, uint32_t* subChannelOut) {
+    if (channelOut) *channelOut = 0;
+    if (subChannelOut) *subChannelOut = 0;
+    if (isAmFm(getType(sel))) {
+        if (channelOut) *channelOut = getId(sel, IdentifierType::AMFM_FREQUENCY);
+        if (subChannelOut && hasId(sel, IdentifierType::HD_SUBCHANNEL)) {
+            // The legacy APIs had 1-based subChannels, while ProgramSelector is 0-based.
+            *subChannelOut = getId(sel, IdentifierType::HD_SUBCHANNEL) + 1;
+        }
+        return true;
+    }
+    return false;
+}
+
+bool isDigital(const ProgramSelector& sel) {
+    switch (getType(sel)) {
+        case ProgramType::AM:
+        case ProgramType::FM:
+            return false;
+        default:
+            // VENDOR might not be digital, but it doesn't matter for default impl.
+            return true;
+    }
+}
+
+}  // namespace utils
+
+namespace V1_0 {
+
+bool operator==(const BandConfig& l, const BandConfig& r) {
+    using namespace utils;
+
+    if (l.type != r.type) return false;
+    if (l.antennaConnected != r.antennaConnected) return false;
+    if (l.lowerLimit != r.lowerLimit) return false;
+    if (l.upperLimit != r.upperLimit) return false;
+    if (l.spacings != r.spacings) return false;
+    if (isAm(l.type)) {
+        return l.ext.am == r.ext.am;
+    } else if (isFm(l.type)) {
+        return l.ext.fm == r.ext.fm;
+    } else {
+        ALOGW("Unsupported band config type: %s", toString(l.type).c_str());
+        return false;
+    }
+}
+
+}  // namespace V1_0
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/common/utils1x/include/broadcastradio-utils-1x/Utils.h b/broadcastradio/common/utils1x/include/broadcastradio-utils-1x/Utils.h
new file mode 100644
index 0000000..5884b5a
--- /dev/null
+++ b/broadcastradio/common/utils1x/include/broadcastradio-utils-1x/Utils.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_1X_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_1X_H
+
+#include <android/hardware/broadcastradio/1.2/types.h>
+#include <chrono>
+#include <queue>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace utils {
+
+enum class HalRevision : uint32_t {
+    V1_0 = 1,
+    V1_1,
+    V1_2,
+};
+
+/**
+ * Checks, if {@code pointer} tunes to {@channel}.
+ *
+ * For example, having a channel {AMFM_FREQUENCY = 103.3}:
+ * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 0} can tune to this channel;
+ * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 1} can't.
+ *
+ * @param pointer selector we're trying to match against channel.
+ * @param channel existing channel.
+ */
+bool tunesTo(const V1_1::ProgramSelector& pointer, const V1_1::ProgramSelector& channel);
+
+V1_1::ProgramType getType(const V1_1::ProgramSelector& sel);
+bool isAmFm(const V1_1::ProgramType type);
+
+bool isAm(const V1_0::Band band);
+bool isFm(const V1_0::Band band);
+
+bool hasId(const V1_1::ProgramSelector& sel, const V1_2::IdentifierType type);
+
+/**
+ * Returns ID (either primary or secondary) for a given program selector.
+ *
+ * If the selector does not contain given type, returns 0 and emits a warning.
+ */
+uint64_t getId(const V1_1::ProgramSelector& sel, const V1_2::IdentifierType type);
+
+/**
+ * Returns ID (either primary or secondary) for a given program selector.
+ *
+ * If the selector does not contain given type, returns default value.
+ */
+uint64_t getId(const V1_1::ProgramSelector& sel, const V1_2::IdentifierType type, uint64_t defval);
+
+V1_1::ProgramSelector make_selector(V1_0::Band band, uint32_t channel, uint32_t subChannel = 0);
+
+bool getLegacyChannel(const V1_1::ProgramSelector& sel, uint32_t* channelOut,
+                      uint32_t* subChannelOut);
+
+bool isDigital(const V1_1::ProgramSelector& sel);
+
+}  // namespace utils
+
+namespace V1_0 {
+
+bool operator==(const BandConfig& l, const BandConfig& r);
+
+}  // namespace V1_0
+
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_1X_H
diff --git a/broadcastradio/common/utils2x/Android.bp b/broadcastradio/common/utils2x/Android.bp
new file mode 100644
index 0000000..aab94f2
--- /dev/null
+++ b/broadcastradio/common/utils2x/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.broadcastradio@common-utils-2x-lib",
+    vendor_available: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    cppflags: [
+        "-std=c++1z",
+    ],
+    srcs: [
+        "Utils.cpp",
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "android.hardware.broadcastradio@2.0",
+    ],
+}
diff --git a/broadcastradio/common/utils2x/Utils.cpp b/broadcastradio/common/utils2x/Utils.cpp
new file mode 100644
index 0000000..6fe9554
--- /dev/null
+++ b/broadcastradio/common/utils2x/Utils.cpp
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BcRadioDef.utils"
+//#define LOG_NDEBUG 0
+
+#include <broadcastradio-utils-2x/Utils.h>
+
+#include <android-base/logging.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace utils {
+
+using V2_0::IdentifierType;
+using V2_0::Metadata;
+using V2_0::MetadataKey;
+using V2_0::ProgramFilter;
+using V2_0::ProgramIdentifier;
+using V2_0::ProgramInfo;
+using V2_0::ProgramListChunk;
+using V2_0::ProgramSelector;
+using V2_0::Properties;
+
+using std::string;
+using std::vector;
+
+IdentifierType getType(uint32_t typeAsInt) {
+    return static_cast<IdentifierType>(typeAsInt);
+}
+
+IdentifierType getType(const ProgramIdentifier& id) {
+    return getType(id.type);
+}
+
+IdentifierIterator::IdentifierIterator(const V2_0::ProgramSelector& sel)
+    : IdentifierIterator(sel, 0) {}
+
+IdentifierIterator::IdentifierIterator(const V2_0::ProgramSelector& sel, size_t pos)
+    : mSel(sel), mPos(pos) {}
+
+IdentifierIterator IdentifierIterator::operator++(int) {
+    auto i = *this;
+    mPos++;
+    return i;
+}
+
+IdentifierIterator& IdentifierIterator::operator++() {
+    ++mPos;
+    return *this;
+}
+
+IdentifierIterator::ref_type IdentifierIterator::operator*() const {
+    if (mPos == 0) return sel().primaryId;
+
+    // mPos is 1-based for secondary identifiers
+    DCHECK(mPos <= sel().secondaryIds.size());
+    return sel().secondaryIds[mPos - 1];
+}
+
+bool IdentifierIterator::operator==(const IdentifierIterator& rhs) const {
+    // Check, if both iterators points at the same selector.
+    if (reinterpret_cast<uintptr_t>(&sel()) != reinterpret_cast<uintptr_t>(&rhs.sel())) {
+        return false;
+    }
+
+    return mPos == rhs.mPos;
+}
+
+IdentifierIterator begin(const V2_0::ProgramSelector& sel) {
+    return IdentifierIterator(sel);
+}
+
+IdentifierIterator end(const V2_0::ProgramSelector& sel) {
+    return IdentifierIterator(sel) + 1 /* primary id */ + sel.secondaryIds.size();
+}
+
+FrequencyBand getBand(uint64_t freq) {
+    // keep in sync with
+    // frameworks/base/services/core/java/com/android/server/broadcastradio/hal2/Utils.java
+    if (freq < 30) return FrequencyBand::UNKNOWN;
+    if (freq < 500) return FrequencyBand::AM_LW;
+    if (freq < 1705) return FrequencyBand::AM_MW;
+    if (freq < 30000) return FrequencyBand::AM_SW;
+    if (freq < 60000) return FrequencyBand::UNKNOWN;
+    if (freq < 110000) return FrequencyBand::FM;
+    return FrequencyBand::UNKNOWN;
+}
+
+static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
+                       const IdentifierType type) {
+    return hasId(a, type) && hasId(b, type);
+}
+
+static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
+                         const IdentifierType type) {
+    if (!bothHaveId(a, b, type)) return false;
+    /* We should check all Ids of a given type (ie. other AF),
+     * but it doesn't matter for default implementation.
+     */
+    return getId(a, type) == getId(b, type);
+}
+
+static int getHdSubchannel(const ProgramSelector& sel) {
+    auto hdsidext = getId(sel, IdentifierType::HD_STATION_ID_EXT, 0);
+    hdsidext >>= 32;        // Station ID number
+    return hdsidext & 0xF;  // HD Radio subchannel
+}
+
+bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
+    auto type = getType(b.primaryId);
+
+    switch (type) {
+        case IdentifierType::HD_STATION_ID_EXT:
+        case IdentifierType::RDS_PI:
+        case IdentifierType::AMFM_FREQUENCY:
+            if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
+            if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
+            return getHdSubchannel(b) == 0 && haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
+        case IdentifierType::DAB_SID_EXT:
+            return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
+        case IdentifierType::DRMO_SERVICE_ID:
+            return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
+        case IdentifierType::SXM_SERVICE_ID:
+            return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
+        default:  // includes all vendor types
+            ALOGW("Unsupported program type: %s", toString(type).c_str());
+            return false;
+    }
+}
+
+static bool maybeGetId(const ProgramSelector& sel, const IdentifierType type, uint64_t* val) {
+    auto itype = static_cast<uint32_t>(type);
+
+    if (sel.primaryId.type == itype) {
+        if (val) *val = sel.primaryId.value;
+        return true;
+    }
+
+    // TODO(twasilczyk): use IdentifierIterator
+    // not optimal, but we don't care in default impl
+    for (auto&& id : sel.secondaryIds) {
+        if (id.type == itype) {
+            if (val) *val = id.value;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool hasId(const ProgramSelector& sel, const IdentifierType type) {
+    return maybeGetId(sel, type, nullptr);
+}
+
+uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
+    uint64_t val;
+
+    if (maybeGetId(sel, type, &val)) {
+        return val;
+    }
+
+    ALOGW("Identifier %s not found", toString(type).c_str());
+    return 0;
+}
+
+uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
+    if (!hasId(sel, type)) return defval;
+    return getId(sel, type);
+}
+
+vector<uint64_t> getAllIds(const ProgramSelector& sel, const IdentifierType type) {
+    vector<uint64_t> ret;
+    auto itype = static_cast<uint32_t>(type);
+
+    if (sel.primaryId.type == itype) ret.push_back(sel.primaryId.value);
+
+    // TODO(twasilczyk): use IdentifierIterator
+    for (auto&& id : sel.secondaryIds) {
+        if (id.type == itype) ret.push_back(id.value);
+    }
+
+    return ret;
+}
+
+bool isSupported(const Properties& prop, const ProgramSelector& sel) {
+    // TODO(twasilczyk): use IdentifierIterator
+    // Not optimal, but it doesn't matter for default impl nor VTS tests.
+    for (auto&& idType : prop.supportedIdentifierTypes) {
+        if (hasId(sel, getType(idType))) return true;
+    }
+    return false;
+}
+
+bool isValid(const ProgramIdentifier& id) {
+    auto val = id.value;
+    bool valid = true;
+
+    auto expect = [&valid](bool condition, std::string message) {
+        if (!condition) {
+            valid = false;
+            ALOGE("Identifier not valid, expected %s", message.c_str());
+        }
+    };
+
+    switch (getType(id)) {
+        case IdentifierType::INVALID:
+            expect(false, "IdentifierType::INVALID");
+            break;
+        case IdentifierType::DAB_FREQUENCY:
+            expect(val > 100000u, "f > 100MHz");
+        // fallthrough
+        case IdentifierType::AMFM_FREQUENCY:
+        case IdentifierType::DRMO_FREQUENCY:
+            expect(val > 100u, "f > 100kHz");
+            expect(val < 10000000u, "f < 10GHz");
+            break;
+        case IdentifierType::RDS_PI:
+            expect(val != 0u, "RDS PI != 0");
+            expect(val <= 0xFFFFu, "16bit id");
+            break;
+        case IdentifierType::HD_STATION_ID_EXT: {
+            auto stationId = val & 0xFFFFFFFF;  // 32bit
+            val >>= 32;
+            auto subchannel = val & 0xF;  // 4bit
+            val >>= 4;
+            auto freq = val & 0x3FFFF;  // 18bit
+            expect(stationId != 0u, "HD station id != 0");
+            expect(subchannel < 8u, "HD subch < 8");
+            expect(freq > 100u, "f > 100kHz");
+            expect(freq < 10000000u, "f < 10GHz");
+            break;
+        }
+        case IdentifierType::HD_STATION_NAME: {
+            while (val > 0) {
+                auto ch = static_cast<char>(val & 0xFF);
+                val >>= 8;
+                expect((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'),
+                       "HD_STATION_NAME does not match [A-Z0-9]+");
+            }
+            break;
+        }
+        case IdentifierType::DAB_SID_EXT: {
+            auto sid = val & 0xFFFF;  // 16bit
+            val >>= 16;
+            auto ecc = val & 0xFF;  // 8bit
+            expect(sid != 0u, "DAB SId != 0");
+            expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
+            break;
+        }
+        case IdentifierType::DAB_ENSEMBLE:
+            expect(val != 0u, "DAB ensemble != 0");
+            expect(val <= 0xFFFFu, "16bit id");
+            break;
+        case IdentifierType::DAB_SCID:
+            expect(val > 0xFu, "12bit SCId (not 4bit SCIdS)");
+            expect(val <= 0xFFFu, "12bit id");
+            break;
+        case IdentifierType::DRMO_SERVICE_ID:
+            expect(val != 0u, "DRM SId != 0");
+            expect(val <= 0xFFFFFFu, "24bit id");
+            break;
+        case IdentifierType::SXM_SERVICE_ID:
+            expect(val != 0u, "SXM SId != 0");
+            expect(val <= 0xFFFFFFFFu, "32bit id");
+            break;
+        case IdentifierType::SXM_CHANNEL:
+            expect(val < 1000u, "SXM channel < 1000");
+            break;
+        case IdentifierType::VENDOR_START:
+        case IdentifierType::VENDOR_END:
+            // skip
+            break;
+    }
+
+    return valid;
+}
+
+bool isValid(const ProgramSelector& sel) {
+    if (!isValid(sel.primaryId)) return false;
+    // TODO(twasilczyk): use IdentifierIterator
+    for (auto&& id : sel.secondaryIds) {
+        if (!isValid(id)) return false;
+    }
+    return true;
+}
+
+ProgramIdentifier make_identifier(IdentifierType type, uint64_t value) {
+    return {static_cast<uint32_t>(type), value};
+}
+
+ProgramSelector make_selector_amfm(uint32_t frequency) {
+    ProgramSelector sel = {};
+    sel.primaryId = make_identifier(IdentifierType::AMFM_FREQUENCY, frequency);
+    return sel;
+}
+
+Metadata make_metadata(MetadataKey key, int64_t value) {
+    Metadata meta = {};
+    meta.key = static_cast<uint32_t>(key);
+    meta.intValue = value;
+    return meta;
+}
+
+Metadata make_metadata(MetadataKey key, string value) {
+    Metadata meta = {};
+    meta.key = static_cast<uint32_t>(key);
+    meta.stringValue = value;
+    return meta;
+}
+
+bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel) {
+    if (filter.identifierTypes.size() > 0) {
+        auto typeEquals = [](const V2_0::ProgramIdentifier& id, uint32_t type) {
+            return id.type == type;
+        };
+        auto it = std::find_first_of(begin(sel), end(sel), filter.identifierTypes.begin(),
+                                     filter.identifierTypes.end(), typeEquals);
+        if (it == end(sel)) return false;
+    }
+
+    if (filter.identifiers.size() > 0) {
+        auto it = std::find_first_of(begin(sel), end(sel), filter.identifiers.begin(),
+                                     filter.identifiers.end());
+        if (it == end(sel)) return false;
+    }
+
+    if (!filter.includeCategories) {
+        if (getType(sel.primaryId) == IdentifierType::DAB_ENSEMBLE) return false;
+    }
+
+    return true;
+}
+
+size_t ProgramInfoHasher::operator()(const ProgramInfo& info) const {
+    auto& id = info.selector.primaryId;
+
+    /* This is not the best hash implementation, but good enough for default HAL
+     * implementation and tests. */
+    auto h = std::hash<uint32_t>{}(id.type);
+    h += 0x9e3779b9;
+    h ^= std::hash<uint64_t>{}(id.value);
+
+    return h;
+}
+
+bool ProgramInfoKeyEqual::operator()(const ProgramInfo& info1, const ProgramInfo& info2) const {
+    auto& id1 = info1.selector.primaryId;
+    auto& id2 = info2.selector.primaryId;
+    return id1.type == id2.type && id1.value == id2.value;
+}
+
+void updateProgramList(ProgramInfoSet& list, const ProgramListChunk& chunk) {
+    if (chunk.purge) list.clear();
+
+    list.insert(chunk.modified.begin(), chunk.modified.end());
+
+    for (auto&& id : chunk.removed) {
+        ProgramInfo info = {};
+        info.selector.primaryId = id;
+        list.erase(info);
+    }
+}
+
+std::optional<std::string> getMetadataString(const V2_0::ProgramInfo& info,
+                                             const V2_0::MetadataKey key) {
+    auto isKey = [key](const V2_0::Metadata& item) {
+        return static_cast<V2_0::MetadataKey>(item.key) == key;
+    };
+
+    auto it = std::find_if(info.metadata.begin(), info.metadata.end(), isKey);
+    if (it == info.metadata.end()) return std::nullopt;
+
+    return it->stringValue;
+}
+
+V2_0::ProgramIdentifier make_hdradio_station_name(const std::string& name) {
+    constexpr size_t maxlen = 8;
+
+    std::string shortName;
+    shortName.reserve(maxlen);
+
+    auto&& loc = std::locale::classic();
+    for (char ch : name) {
+        if (!std::isalnum(ch, loc)) continue;
+        shortName.push_back(std::toupper(ch, loc));
+        if (shortName.length() >= maxlen) break;
+    }
+
+    uint64_t val = 0;
+    for (auto rit = shortName.rbegin(); rit != shortName.rend(); ++rit) {
+        val <<= 8;
+        val |= static_cast<uint8_t>(*rit);
+    }
+
+    return make_identifier(IdentifierType::HD_STATION_NAME, val);
+}
+
+}  // namespace utils
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h b/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h
new file mode 100644
index 0000000..5e51941
--- /dev/null
+++ b/broadcastradio/common/utils2x/include/broadcastradio-utils-2x/Utils.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_2X_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_2X_H
+
+#include <android/hardware/broadcastradio/2.0/types.h>
+#include <chrono>
+#include <optional>
+#include <queue>
+#include <thread>
+#include <unordered_set>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace utils {
+
+enum class FrequencyBand {
+    UNKNOWN,
+    FM,
+    AM_LW,
+    AM_MW,
+    AM_SW,
+};
+
+V2_0::IdentifierType getType(uint32_t typeAsInt);
+V2_0::IdentifierType getType(const V2_0::ProgramIdentifier& id);
+
+class IdentifierIterator
+    : public std::iterator<std::random_access_iterator_tag, V2_0::ProgramIdentifier, ssize_t,
+                           const V2_0::ProgramIdentifier*, const V2_0::ProgramIdentifier&> {
+    using traits = std::iterator_traits<IdentifierIterator>;
+    using ptr_type = typename traits::pointer;
+    using ref_type = typename traits::reference;
+    using diff_type = typename traits::difference_type;
+
+   public:
+    explicit IdentifierIterator(const V2_0::ProgramSelector& sel);
+
+    IdentifierIterator operator++(int);
+    IdentifierIterator& operator++();
+    ref_type operator*() const;
+    inline ptr_type operator->() const { return &operator*(); }
+    IdentifierIterator operator+(diff_type v) const { return IdentifierIterator(mSel, mPos + v); }
+    bool operator==(const IdentifierIterator& rhs) const;
+    inline bool operator!=(const IdentifierIterator& rhs) const { return !operator==(rhs); };
+
+   private:
+    explicit IdentifierIterator(const V2_0::ProgramSelector& sel, size_t pos);
+
+    std::reference_wrapper<const V2_0::ProgramSelector> mSel;
+
+    const V2_0::ProgramSelector& sel() const { return mSel.get(); }
+
+    /** 0 is the primary identifier, 1-n are secondary identifiers. */
+    size_t mPos = 0;
+};
+
+IdentifierIterator begin(const V2_0::ProgramSelector& sel);
+IdentifierIterator end(const V2_0::ProgramSelector& sel);
+
+/**
+ * Guesses band from the frequency value.
+ *
+ * The band bounds are not exact to cover multiple regions.
+ * The function is biased towards success, i.e. it never returns
+ * FrequencyBand::UNKNOWN for correct frequency, but a result for
+ * incorrect one is undefined (it doesn't have to return UNKNOWN).
+ */
+FrequencyBand getBand(uint64_t frequency);
+
+/**
+ * Checks, if {@code pointer} tunes to {@channel}.
+ *
+ * For example, having a channel {AMFM_FREQUENCY = 103.3}:
+ * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 0} can tune to this channel;
+ * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 1} can't.
+ *
+ * @param pointer selector we're trying to match against channel.
+ * @param channel existing channel.
+ */
+bool tunesTo(const V2_0::ProgramSelector& pointer, const V2_0::ProgramSelector& channel);
+
+bool hasId(const V2_0::ProgramSelector& sel, const V2_0::IdentifierType type);
+
+/**
+ * Returns ID (either primary or secondary) for a given program selector.
+ *
+ * If the selector does not contain given type, returns 0 and emits a warning.
+ */
+uint64_t getId(const V2_0::ProgramSelector& sel, const V2_0::IdentifierType type);
+
+/**
+ * Returns ID (either primary or secondary) for a given program selector.
+ *
+ * If the selector does not contain given type, returns default value.
+ */
+uint64_t getId(const V2_0::ProgramSelector& sel, const V2_0::IdentifierType type, uint64_t defval);
+
+/**
+ * Returns all IDs of a given type.
+ */
+std::vector<uint64_t> getAllIds(const V2_0::ProgramSelector& sel, const V2_0::IdentifierType type);
+
+/**
+ * Checks, if a given selector is supported by the radio module.
+ *
+ * @param prop Module description.
+ * @param sel The selector to check.
+ * @return True, if the selector is supported, false otherwise.
+ */
+bool isSupported(const V2_0::Properties& prop, const V2_0::ProgramSelector& sel);
+
+bool isValid(const V2_0::ProgramIdentifier& id);
+bool isValid(const V2_0::ProgramSelector& sel);
+
+V2_0::ProgramIdentifier make_identifier(V2_0::IdentifierType type, uint64_t value);
+V2_0::ProgramSelector make_selector_amfm(uint32_t frequency);
+V2_0::Metadata make_metadata(V2_0::MetadataKey key, int64_t value);
+V2_0::Metadata make_metadata(V2_0::MetadataKey key, std::string value);
+
+bool satisfies(const V2_0::ProgramFilter& filter, const V2_0::ProgramSelector& sel);
+
+struct ProgramInfoHasher {
+    size_t operator()(const V2_0::ProgramInfo& info) const;
+};
+
+struct ProgramInfoKeyEqual {
+    bool operator()(const V2_0::ProgramInfo& info1, const V2_0::ProgramInfo& info2) const;
+};
+
+typedef std::unordered_set<V2_0::ProgramInfo, ProgramInfoHasher, ProgramInfoKeyEqual>
+    ProgramInfoSet;
+
+void updateProgramList(ProgramInfoSet& list, const V2_0::ProgramListChunk& chunk);
+
+std::optional<std::string> getMetadataString(const V2_0::ProgramInfo& info,
+                                             const V2_0::MetadataKey key);
+
+V2_0::ProgramIdentifier make_hdradio_station_name(const std::string& name);
+
+}  // namespace utils
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_COMMON_UTILS_2X_H
diff --git a/broadcastradio/common/vts/utils/Android.bp b/broadcastradio/common/vts/utils/Android.bp
new file mode 100644
index 0000000..4ba8a17
--- /dev/null
+++ b/broadcastradio/common/vts/utils/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.broadcastradio@vts-utils-lib",
+    srcs: [
+        "call-barrier.cpp",
+    ],
+    export_include_dirs: ["include"],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+}
diff --git a/broadcastradio/1.1/vts/utils/call-barrier.cpp b/broadcastradio/common/vts/utils/call-barrier.cpp
similarity index 100%
rename from broadcastradio/1.1/vts/utils/call-barrier.cpp
rename to broadcastradio/common/vts/utils/call-barrier.cpp
diff --git a/broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/call-barrier.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/call-barrier.h
similarity index 100%
rename from broadcastradio/1.1/vts/utils/include/broadcastradio-vts-utils/call-barrier.h
rename to broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/call-barrier.h
diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h
new file mode 100644
index 0000000..1f716f1
--- /dev/null
+++ b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/mock-timeout.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_VTS_MOCK_TIMEOUT
+#define ANDROID_HARDWARE_BROADCASTRADIO_VTS_MOCK_TIMEOUT
+
+#include <gmock/gmock.h>
+#include <thread>
+
+#ifndef EGMOCK_VERBOSE
+#define EGMOCK_VERBOSE 0
+#endif
+
+/**
+ * Print log message.
+ *
+ * INTERNAL IMPLEMENTATION - don't use in user code.
+ */
+#if EGMOCK_VERBOSE
+#define EGMOCK_LOG_(...) ALOGV("egmock: " __VA_ARGS__)
+#else
+#define EGMOCK_LOG_(...)
+#endif
+
+/**
+ * Common helper objects for gmock timeout extension.
+ *
+ * INTERNAL IMPLEMENTATION - don't use in user code.
+ */
+#define EGMOCK_TIMEOUT_METHOD_DEF_(Method, ...) \
+    std::atomic<bool> egmock_called_##Method;   \
+    std::mutex egmock_mut_##Method;             \
+    std::condition_variable egmock_cond_##Method;
+
+/**
+ * Function similar to comma operator, to make it possible to return any value returned by mocked
+ * function (which may be void) and discard the result of the other operation (notification about
+ * a call).
+ *
+ * We need to invoke the mocked function (which result is returned) before the notification (which
+ * result is dropped) - that's exactly the opposite of comma operator.
+ *
+ * INTERNAL IMPLEMENTATION - don't use in user code.
+ */
+template <typename T>
+static T EGMockFlippedComma_(std::function<T()> returned, std::function<void()> discarded) {
+    auto ret = returned();
+    discarded();
+    return ret;
+}
+
+template <>
+inline void EGMockFlippedComma_(std::function<void()> returned, std::function<void()> discarded) {
+    returned();
+    discarded();
+}
+
+/**
+ * Common method body for gmock timeout extension.
+ *
+ * INTERNAL IMPLEMENTATION - don't use in user code.
+ */
+#define EGMOCK_TIMEOUT_METHOD_BODY_(Method, ...)                      \
+    auto invokeMock = [&]() { return egmock_##Method(__VA_ARGS__); }; \
+    auto notify = [&]() {                                             \
+        std::lock_guard<std::mutex> lk(egmock_mut_##Method);          \
+        EGMOCK_LOG_(#Method " called");                               \
+        egmock_called_##Method = true;                                \
+        egmock_cond_##Method.notify_all();                            \
+    };                                                                \
+    return EGMockFlippedComma_<decltype(invokeMock())>(invokeMock, notify);
+
+/**
+ * Gmock MOCK_METHOD0 timeout-capable extension.
+ */
+#define MOCK_TIMEOUT_METHOD0(Method, ...)       \
+    MOCK_METHOD0(egmock_##Method, __VA_ARGS__); \
+    EGMOCK_TIMEOUT_METHOD_DEF_(Method);         \
+    virtual GMOCK_RESULT_(, __VA_ARGS__) Method() { EGMOCK_TIMEOUT_METHOD_BODY_(Method); }
+
+/**
+ * Gmock MOCK_METHOD1 timeout-capable extension.
+ */
+#define MOCK_TIMEOUT_METHOD1(Method, ...)                                                 \
+    MOCK_METHOD1(egmock_##Method, __VA_ARGS__);                                           \
+    EGMOCK_TIMEOUT_METHOD_DEF_(Method);                                                   \
+    virtual GMOCK_RESULT_(, __VA_ARGS__) Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1) { \
+        EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1);                                   \
+    }
+
+/**
+ * Gmock MOCK_METHOD2 timeout-capable extension.
+ */
+#define MOCK_TIMEOUT_METHOD2(Method, ...)                                                        \
+    MOCK_METHOD2(egmock_##Method, __VA_ARGS__);                                                  \
+    EGMOCK_TIMEOUT_METHOD_DEF_(Method);                                                          \
+    virtual GMOCK_RESULT_(, __VA_ARGS__)                                                         \
+        Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1, GMOCK_ARG_(, 2, __VA_ARGS__) egmock_a2) { \
+        EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1, egmock_a2);                               \
+    }
+
+/**
+ * Gmock EXPECT_CALL timeout-capable extension.
+ *
+ * It has slightly different syntax from the original macro, to make method name accessible.
+ * So, instead of typing
+ *     EXPECT_CALL(account, charge(100, Currency::USD));
+ * you need to inline arguments
+ *     EXPECT_TIMEOUT_CALL(account, charge, 100, Currency::USD);
+ */
+#define EXPECT_TIMEOUT_CALL(obj, Method, ...) \
+    EGMOCK_LOG_(#Method " expected to call"); \
+    (obj).egmock_called_##Method = false;     \
+    EXPECT_CALL(obj, egmock_##Method(__VA_ARGS__))
+
+/**
+ * Waits for an earlier EXPECT_TIMEOUT_CALL to execute.
+ *
+ * It does not fully support special constraints of the EXPECT_CALL clause, just proceeds when the
+ * first call to a given method comes. For example, in the following code:
+ *     EXPECT_TIMEOUT_CALL(account, charge, 100, _);
+ *     account.charge(50, Currency::USD);
+ *     EXPECT_TIMEOUT_CALL_WAIT(account, charge, 500ms);
+ * the wait clause will just continue, as the charge method was called.
+ *
+ * @param obj object for a call
+ * @param Method the method to wait for
+ * @param timeout the maximum time for waiting
+ */
+#define EXPECT_TIMEOUT_CALL_WAIT(obj, Method, timeout)                      \
+    {                                                                       \
+        EGMOCK_LOG_("waiting for " #Method " call");                        \
+        std::unique_lock<std::mutex> lk((obj).egmock_mut_##Method);         \
+        if (!(obj).egmock_called_##Method) {                                \
+            auto status = (obj).egmock_cond_##Method.wait_for(lk, timeout); \
+            EXPECT_EQ(std::cv_status::no_timeout, status);                  \
+        }                                                                   \
+    }
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_VTS_MOCK_TIMEOUT
diff --git a/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/pointer-utils.h b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/pointer-utils.h
new file mode 100644
index 0000000..0b6f5eb
--- /dev/null
+++ b/broadcastradio/common/vts/utils/include/broadcastradio-vts-utils/pointer-utils.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_VTS_POINTER_UTILS
+#define ANDROID_HARDWARE_BROADCASTRADIO_VTS_POINTER_UTILS
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace vts {
+
+/**
+ * Clears strong pointer and waits until the object gets destroyed.
+ *
+ * @param ptr The pointer to get cleared.
+ * @param timeout Time to wait for other references.
+ */
+template <typename T>
+static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) {
+    using std::chrono::steady_clock;
+
+    constexpr auto step = 10ms;
+
+    wp<T> wptr = ptr;
+    ptr.clear();
+
+    auto limit = steady_clock::now() + timeout;
+    while (wptr.promote() != nullptr) {
+        if (steady_clock::now() + step > limit) {
+            FAIL() << "Pointer was not released within timeout";
+            break;
+        }
+        std::this_thread::sleep_for(step);
+    }
+}
+
+}  // namespace vts
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_VTS_POINTER_UTILS
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
index 6209cb8..21f81f5 100644
--- a/camera/common/1.0/default/Android.bp
+++ b/camera/common/1.0/default/Android.bp
@@ -7,7 +7,9 @@
         "CameraMetadata.cpp",
         "CameraParameters.cpp",
         "VendorTagDescriptor.cpp",
-        "HandleImporter.cpp"],
+        "HandleImporter.cpp",
+        "Exif.cpp"
+    ],
     cflags: [
         "-Werror",
         "-Wextra",
@@ -17,7 +19,9 @@
         "liblog",
         "libhardware",
         "libcamera_metadata",
-        "android.hardware.graphics.mapper@2.0"],
+        "android.hardware.graphics.mapper@2.0",
+        "libexif",
+    ],
     include_dirs: ["system/media/private/camera/include"],
     export_include_dirs : ["include"]
 }
diff --git a/camera/common/1.0/default/Exif.cpp b/camera/common/1.0/default/Exif.cpp
new file mode 100644
index 0000000..3e894f9
--- /dev/null
+++ b/camera/common/1.0/default/Exif.cpp
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamComm1.0-Exif"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "Exif.h"
+
+extern "C" {
+#include <libexif/exif-data.h>
+}
+
+namespace std {
+
+template <>
+struct default_delete<ExifEntry> {
+    inline void operator()(ExifEntry* entry) const { exif_entry_unref(entry); }
+};
+
+}  // namespace std
+
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+
+class ExifUtilsImpl : public ExifUtils {
+  public:
+    ExifUtilsImpl();
+
+    virtual ~ExifUtilsImpl();
+
+    // Initialize() can be called multiple times. The setting of Exif tags will be
+    // cleared.
+    virtual bool initialize();
+
+    // set all known fields from a metadata structure
+    virtual bool setFromMetadata(const CameraMetadata& metadata,
+                                 const size_t imageWidth,
+                                 const size_t imageHeight);
+
+    // sets the len aperture.
+    // Returns false if memory allocation fails.
+    virtual bool setAperture(uint32_t numerator, uint32_t denominator);
+
+    // sets the value of brightness.
+    // Returns false if memory allocation fails.
+    virtual bool setBrightness(int32_t numerator, int32_t denominator);
+
+    // sets the color space.
+    // Returns false if memory allocation fails.
+    virtual bool setColorSpace(uint16_t color_space);
+
+    // sets the information to compressed data.
+    // Returns false if memory allocation fails.
+    virtual bool setComponentsConfiguration(const std::string& components_configuration);
+
+    // sets the compression scheme used for the image data.
+    // Returns false if memory allocation fails.
+    virtual bool setCompression(uint16_t compression);
+
+    // sets image contrast.
+    // Returns false if memory allocation fails.
+    virtual bool setContrast(uint16_t contrast);
+
+    // sets the date and time of image last modified. It takes local time. The
+    // name of the tag is DateTime in IFD0.
+    // Returns false if memory allocation fails.
+    virtual bool setDateTime(const struct tm& t);
+
+    // sets the image description.
+    // Returns false if memory allocation fails.
+    virtual bool setDescription(const std::string& description);
+
+    // sets the digital zoom ratio. If the numerator is 0, it means digital zoom
+    // was not used.
+    // Returns false if memory allocation fails.
+    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator);
+
+    // sets the exposure bias.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureBias(int32_t numerator, int32_t denominator);
+
+    // sets the exposure mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureMode(uint16_t exposure_mode);
+
+    // sets the program used by the camera to set exposure when the picture is
+    // taken.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureProgram(uint16_t exposure_program);
+
+    // sets the exposure time, given in seconds.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator);
+
+    // sets the status of flash.
+    // Returns false if memory allocation fails.
+    virtual bool setFlash(uint16_t flash);
+
+    // sets the F number.
+    // Returns false if memory allocation fails.
+    virtual bool setFNumber(uint32_t numerator, uint32_t denominator);
+
+    // sets the focal length of lens used to take the image in millimeters.
+    // Returns false if memory allocation fails.
+    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator);
+
+    // sets the degree of overall image gain adjustment.
+    // Returns false if memory allocation fails.
+    virtual bool setGainControl(uint16_t gain_control);
+
+    // sets the altitude in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsAltitude(double altitude);
+
+    // sets the latitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLatitude(double latitude);
+
+    // sets the longitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLongitude(double longitude);
+
+    // sets GPS processing method.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsProcessingMethod(const std::string& method);
+
+    // sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsTimestamp(const struct tm& t);
+
+    // sets the length (number of rows) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageHeight(uint32_t length);
+
+    // sets the width (number of columes) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageWidth(uint32_t width);
+
+    // sets the ISO speed.
+    // Returns false if memory allocation fails.
+    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings);
+
+    // sets the kind of light source.
+    // Returns false if memory allocation fails.
+    virtual bool setLightSource(uint16_t light_source);
+
+    // sets the smallest F number of the lens.
+    // Returns false if memory allocation fails.
+    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator);
+
+    // sets the metering mode.
+    // Returns false if memory allocation fails.
+    virtual bool setMeteringMode(uint16_t metering_mode);
+
+    // sets image orientation.
+    // Returns false if memory allocation fails.
+    virtual bool setOrientation(uint16_t orientation);
+
+    // sets the unit for measuring XResolution and YResolution.
+    // Returns false if memory allocation fails.
+    virtual bool setResolutionUnit(uint16_t resolution_unit);
+
+    // sets image saturation.
+    // Returns false if memory allocation fails.
+    virtual bool setSaturation(uint16_t saturation);
+
+    // sets the type of scene that was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setSceneCaptureType(uint16_t type);
+
+    // sets image sharpness.
+    // Returns false if memory allocation fails.
+    virtual bool setSharpness(uint16_t sharpness);
+
+    // sets the shutter speed.
+    // Returns false if memory allocation fails.
+    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator);
+
+    // sets the distance to the subject, given in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator);
+
+    // sets the fractions of seconds for the <DateTime> tag.
+    // Returns false if memory allocation fails.
+    virtual bool setSubsecTime(const std::string& subsec_time);
+
+    // sets the white balance mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setWhiteBalance(uint16_t white_balance);
+
+    // sets the number of pixels per resolution unit in the image width.
+    // Returns false if memory allocation fails.
+    virtual bool setXResolution(uint32_t numerator, uint32_t denominator);
+
+    // sets the position of chrominance components in relation to the luminance
+    // component.
+    // Returns false if memory allocation fails.
+    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning);
+
+    // sets the number of pixels per resolution unit in the image length.
+    // Returns false if memory allocation fails.
+    virtual bool setYResolution(uint32_t numerator, uint32_t denominator);
+
+    // sets the manufacturer of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setMake(const std::string& make);
+
+    // sets the model number of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setModel(const std::string& model);
+
+    // Generates APP1 segment.
+    // Returns false if generating APP1 segment fails.
+    virtual bool generateApp1(const void* thumbnail_buffer, uint32_t size);
+
+    // Gets buffer of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual const uint8_t* getApp1Buffer();
+
+    // Gets length of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual unsigned int getApp1Length();
+
+  protected:
+    // sets the version of this standard supported.
+    // Returns false if memory allocation fails.
+    virtual bool setExifVersion(const std::string& exif_version);
+
+
+    // Resets the pointers and memories.
+    virtual void reset();
+
+    // Adds a variable length tag to |exif_data_|. It will remove the original one
+    // if the tag exists.
+    // Returns the entry of the tag. The reference count of returned ExifEntry is
+    // two.
+    virtual std::unique_ptr<ExifEntry> addVariableLengthEntry(ExifIfd ifd,
+                                                              ExifTag tag,
+                                                              ExifFormat format,
+                                                              uint64_t components,
+                                                              unsigned int size);
+
+    // Adds a entry of |tag| in |exif_data_|. It won't remove the original one if
+    // the tag exists.
+    // Returns the entry of the tag. It adds one reference count to returned
+    // ExifEntry.
+    virtual std::unique_ptr<ExifEntry> addEntry(ExifIfd ifd, ExifTag tag);
+
+    // Helpe functions to add exif data with different types.
+    virtual bool setShort(ExifIfd ifd,
+                          ExifTag tag,
+                          uint16_t value,
+                          const std::string& msg);
+
+    virtual bool setLong(ExifIfd ifd,
+                         ExifTag tag,
+                         uint32_t value,
+                         const std::string& msg);
+
+    virtual bool setRational(ExifIfd ifd,
+                             ExifTag tag,
+                             uint32_t numerator,
+                             uint32_t denominator,
+                             const std::string& msg);
+
+    virtual bool setSRational(ExifIfd ifd,
+                              ExifTag tag,
+                              int32_t numerator,
+                              int32_t denominator,
+                              const std::string& msg);
+
+    virtual bool setString(ExifIfd ifd,
+                           ExifTag tag,
+                           ExifFormat format,
+                           const std::string& buffer,
+                           const std::string& msg);
+
+    // Destroys the buffer of APP1 segment if exists.
+    virtual void destroyApp1();
+
+    // The Exif data (APP1). Owned by this class.
+    ExifData* exif_data_;
+    // The raw data of APP1 segment. It's allocated by ExifMem in |exif_data_| but
+    // owned by this class.
+    uint8_t* app1_buffer_;
+    // The length of |app1_buffer_|.
+    unsigned int app1_length_;
+
+};
+
+#define SET_SHORT(ifd, tag, value)                      \
+    do {                                                \
+        if (setShort(ifd, tag, value, #tag) == false)   \
+            return false;                               \
+    } while (0);
+
+#define SET_LONG(ifd, tag, value)                       \
+    do {                                                \
+        if (setLong(ifd, tag, value, #tag) == false)    \
+            return false;                               \
+    } while (0);
+
+#define SET_RATIONAL(ifd, tag, numerator, denominator)                      \
+    do {                                                                    \
+        if (setRational(ifd, tag, numerator, denominator, #tag) == false)   \
+            return false;                                                   \
+    } while (0);
+
+#define SET_SRATIONAL(ifd, tag, numerator, denominator)                       \
+    do {                                                                      \
+        if (setSRational(ifd, tag, numerator, denominator, #tag) == false)    \
+            return false;                                                     \
+    } while (0);
+
+#define SET_STRING(ifd, tag, format, buffer)                                  \
+    do {                                                                      \
+        if (setString(ifd, tag, format, buffer, #tag) == false)               \
+            return false;                                                     \
+    } while (0);
+
+// This comes from the Exif Version 2.2 standard table 6.
+const char gExifAsciiPrefix[] = {0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0};
+
+static void setLatitudeOrLongitudeData(unsigned char* data, double num) {
+    // Take the integer part of |num|.
+    ExifLong degrees = static_cast<ExifLong>(num);
+    ExifLong minutes = static_cast<ExifLong>(60 * (num - degrees));
+    ExifLong microseconds =
+            static_cast<ExifLong>(3600000000u * (num - degrees - minutes / 60.0));
+    exif_set_rational(data, EXIF_BYTE_ORDER_INTEL, {degrees, 1});
+    exif_set_rational(data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                                        {minutes, 1});
+    exif_set_rational(data + 2 * sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                                        {microseconds, 1000000});
+}
+
+ExifUtils *ExifUtils::create() {
+    return new ExifUtilsImpl();
+}
+
+ExifUtils::~ExifUtils() {
+}
+
+ExifUtilsImpl::ExifUtilsImpl()
+        : exif_data_(nullptr), app1_buffer_(nullptr), app1_length_(0) {}
+
+ExifUtilsImpl::~ExifUtilsImpl() {
+    reset();
+}
+
+
+bool ExifUtilsImpl::initialize() {
+    reset();
+    exif_data_ = exif_data_new();
+    if (exif_data_ == nullptr) {
+        ALOGE("%s: allocate memory for exif_data_ failed", __FUNCTION__);
+        return false;
+    }
+    // set the image options.
+    exif_data_set_option(exif_data_, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
+    exif_data_set_data_type(exif_data_, EXIF_DATA_TYPE_COMPRESSED);
+    exif_data_set_byte_order(exif_data_, EXIF_BYTE_ORDER_INTEL);
+
+    // set exif version to 2.2.
+    if (!setExifVersion("0220")) {
+        return false;
+    }
+
+    return true;
+}
+
+bool ExifUtilsImpl::setAperture(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_APERTURE_VALUE, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setBrightness(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_BRIGHTNESS_VALUE, numerator,
+                                denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setColorSpace(uint16_t color_space) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE, color_space);
+    return true;
+}
+
+bool ExifUtilsImpl::setComponentsConfiguration(
+        const std::string& components_configuration) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION,
+                          EXIF_FORMAT_UNDEFINED, components_configuration);
+    return true;
+}
+
+bool ExifUtilsImpl::setCompression(uint16_t compression) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_COMPRESSION, compression);
+    return true;
+}
+
+bool ExifUtilsImpl::setContrast(uint16_t contrast) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_CONTRAST, contrast);
+    return true;
+}
+
+bool ExifUtilsImpl::setDateTime(const struct tm& t) {
+    // The length is 20 bytes including NULL for termination in Exif standard.
+    char str[20];
+    int result = snprintf(str, sizeof(str), "%04i:%02i:%02i %02i:%02i:%02i",
+                                                t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
+                                                t.tm_min, t.tm_sec);
+    if (result != sizeof(str) - 1) {
+        ALOGW("%s: Input time is invalid", __FUNCTION__);
+        return false;
+    }
+    std::string buffer(str);
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, buffer);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII,
+                          buffer);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII,
+                          buffer);
+    return true;
+}
+
+bool ExifUtilsImpl::setDescription(const std::string& description) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, EXIF_FORMAT_ASCII,
+                          description);
+    return true;
+}
+
+bool ExifUtilsImpl::setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_DIGITAL_ZOOM_RATIO, numerator,
+                              denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureBias(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE, numerator,
+                                denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureMode(uint16_t exposure_mode) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE, exposure_mode);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureProgram(uint16_t exposure_program) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM, exposure_program);
+    return true;
+}
+
+bool ExifUtilsImpl::setExposureTime(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setFlash(uint16_t flash) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_FLASH, flash);
+    return true;
+}
+
+bool ExifUtilsImpl::setFNumber(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setFocalLength(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setGainControl(uint16_t gain_control) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_GAIN_CONTROL, gain_control);
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsAltitude(double altitude) {
+    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_BYTE, 1, 1);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSAltitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (altitude >= 0) {
+        *refEntry->data = 0;
+    } else {
+        *refEntry->data = 1;
+        altitude *= -1;
+    }
+
+    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_ALTITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 1, sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSAltitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(altitude * 1000), 1000});
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsLatitude(double latitude) {
+    const ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSLatitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (latitude >= 0) {
+        memcpy(refEntry->data, "N", sizeof("N"));
+    } else {
+        memcpy(refEntry->data, "S", sizeof("S"));
+        latitude *= -1;
+    }
+
+    const ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LATITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSLatitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    setLatitudeOrLongitudeData(entry->data, latitude);
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsLongitude(double longitude) {
+    ExifTag refTag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE_REF);
+    std::unique_ptr<ExifEntry> refEntry =
+            addVariableLengthEntry(EXIF_IFD_GPS, refTag, EXIF_FORMAT_ASCII, 2, 2);
+    if (!refEntry) {
+        ALOGE("%s: Adding GPSLongitudeRef exif entry failed", __FUNCTION__);
+        return false;
+    }
+    if (longitude >= 0) {
+        memcpy(refEntry->data, "E", sizeof("E"));
+    } else {
+        memcpy(refEntry->data, "W", sizeof("W"));
+        longitude *= -1;
+    }
+
+    ExifTag tag = static_cast<ExifTag>(EXIF_TAG_GPS_LONGITUDE);
+    std::unique_ptr<ExifEntry> entry = addVariableLengthEntry(
+            EXIF_IFD_GPS, tag, EXIF_FORMAT_RATIONAL, 3, 3 * sizeof(ExifRational));
+    if (!entry) {
+        exif_content_remove_entry(exif_data_->ifd[EXIF_IFD_GPS], refEntry.get());
+        ALOGE("%s: Adding GPSLongitude exif entry failed", __FUNCTION__);
+        return false;
+    }
+    setLatitudeOrLongitudeData(entry->data, longitude);
+
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsProcessingMethod(const std::string& method) {
+    std::string buffer =
+            std::string(gExifAsciiPrefix, sizeof(gExifAsciiPrefix)) + method;
+    SET_STRING(EXIF_IFD_GPS, static_cast<ExifTag>(EXIF_TAG_GPS_PROCESSING_METHOD),
+                          EXIF_FORMAT_UNDEFINED, buffer);
+    return true;
+}
+
+bool ExifUtilsImpl::setGpsTimestamp(const struct tm& t) {
+    const ExifTag dateTag = static_cast<ExifTag>(EXIF_TAG_GPS_DATE_STAMP);
+    const size_t kGpsDateStampSize = 11;
+    std::unique_ptr<ExifEntry> entry =
+            addVariableLengthEntry(EXIF_IFD_GPS, dateTag, EXIF_FORMAT_ASCII,
+                                                          kGpsDateStampSize, kGpsDateStampSize);
+    if (!entry) {
+        ALOGE("%s: Adding GPSDateStamp exif entry failed", __FUNCTION__);
+        return false;
+    }
+    int result =
+            snprintf(reinterpret_cast<char*>(entry->data), kGpsDateStampSize,
+                              "%04i:%02i:%02i", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday);
+    if (result != kGpsDateStampSize - 1) {
+        ALOGW("%s: Input time is invalid", __FUNCTION__);
+        return false;
+    }
+
+    const ExifTag timeTag = static_cast<ExifTag>(EXIF_TAG_GPS_TIME_STAMP);
+    entry = addVariableLengthEntry(EXIF_IFD_GPS, timeTag, EXIF_FORMAT_RATIONAL, 3,
+                                                                  3 * sizeof(ExifRational));
+    if (!entry) {
+        ALOGE("%s: Adding GPSTimeStamp exif entry failed", __FUNCTION__);
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(t.tm_hour), 1});
+    exif_set_rational(entry->data + sizeof(ExifRational), EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(t.tm_min), 1});
+    exif_set_rational(entry->data + 2 * sizeof(ExifRational),
+                                        EXIF_BYTE_ORDER_INTEL,
+                                        {static_cast<ExifLong>(t.tm_sec), 1});
+
+    return true;
+}
+
+bool ExifUtilsImpl::setImageHeight(uint32_t length) {
+    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, length);
+    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, length);
+    return true;
+}
+
+bool ExifUtilsImpl::setImageWidth(uint32_t width) {
+    SET_LONG(EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, width);
+    SET_LONG(EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, width);
+    return true;
+}
+
+bool ExifUtilsImpl::setIsoSpeedRating(uint16_t iso_speed_ratings) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, iso_speed_ratings);
+    return true;
+}
+
+bool ExifUtilsImpl::setLightSource(uint16_t light_source) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_LIGHT_SOURCE, light_source);
+    return true;
+}
+
+bool ExifUtilsImpl::setMaxAperture(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_MAX_APERTURE_VALUE, numerator,
+                              denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setMeteringMode(uint16_t metering_mode) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE, metering_mode);
+    return true;
+}
+
+bool ExifUtilsImpl::setOrientation(uint16_t orientation) {
+    /*
+     * Orientation value:
+     *  1      2      3      4      5          6          7          8
+     *
+     *  888888 888888     88 88     8888888888 88                 88 8888888888
+     *  88         88     88 88     88  88     88  88         88  88     88  88
+     *  8888     8888   8888 8888   88         8888888888 8888888888         88
+     *  88         88     88 88
+     *  88         88 888888 888888
+     */
+    int value = 1;
+    switch (orientation) {
+        case 90:
+            value = 6;
+            break;
+        case 180:
+            value = 3;
+            break;
+        case 270:
+            value = 8;
+            break;
+        default:
+            break;
+    }
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_ORIENTATION, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setResolutionUnit(uint16_t resolution_unit) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_RESOLUTION_UNIT, resolution_unit);
+    return true;
+}
+
+bool ExifUtilsImpl::setSaturation(uint16_t saturation) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SATURATION, saturation);
+    return true;
+}
+
+bool ExifUtilsImpl::setSceneCaptureType(uint16_t type) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SCENE_CAPTURE_TYPE, type);
+    return true;
+}
+
+bool ExifUtilsImpl::setSharpness(uint16_t sharpness) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_SHARPNESS, sharpness);
+    return true;
+}
+
+bool ExifUtilsImpl::setShutterSpeed(int32_t numerator, int32_t denominator) {
+    SET_SRATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE, numerator,
+                                denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setSubjectDistance(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_DISTANCE, numerator,
+                              denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setSubsecTime(const std::string& subsec_time) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME, EXIF_FORMAT_ASCII,
+                          subsec_time);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_FORMAT_ASCII,
+                          subsec_time);
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_FORMAT_ASCII,
+                          subsec_time);
+    return true;
+}
+
+bool ExifUtilsImpl::setWhiteBalance(uint16_t white_balance) {
+    SET_SHORT(EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, white_balance);
+    return true;
+}
+
+bool ExifUtilsImpl::setXResolution(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_X_RESOLUTION, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::setYCbCrPositioning(uint16_t ycbcr_positioning) {
+    SET_SHORT(EXIF_IFD_0, EXIF_TAG_YCBCR_POSITIONING, ycbcr_positioning);
+    return true;
+}
+
+bool ExifUtilsImpl::setYResolution(uint32_t numerator, uint32_t denominator) {
+    SET_RATIONAL(EXIF_IFD_EXIF, EXIF_TAG_Y_RESOLUTION, numerator, denominator);
+    return true;
+}
+
+bool ExifUtilsImpl::generateApp1(const void* thumbnail_buffer, uint32_t size) {
+    destroyApp1();
+    exif_data_->data = const_cast<uint8_t*>(static_cast<const uint8_t*>(thumbnail_buffer));
+    exif_data_->size = size;
+    // Save the result into |app1_buffer_|.
+    exif_data_save_data(exif_data_, &app1_buffer_, &app1_length_);
+    if (!app1_length_) {
+        ALOGE("%s: Allocate memory for app1_buffer_ failed", __FUNCTION__);
+        return false;
+    }
+    /*
+     * The JPEG segment size is 16 bits in spec. The size of APP1 segment should
+     * be smaller than 65533 because there are two bytes for segment size field.
+     */
+    if (app1_length_ > 65533) {
+        destroyApp1();
+        ALOGE("%s: The size of APP1 segment is too large", __FUNCTION__);
+        return false;
+    }
+    return true;
+}
+
+const uint8_t* ExifUtilsImpl::getApp1Buffer() {
+    return app1_buffer_;
+}
+
+unsigned int ExifUtilsImpl::getApp1Length() {
+    return app1_length_;
+}
+
+bool ExifUtilsImpl::setExifVersion(const std::string& exif_version) {
+    SET_STRING(EXIF_IFD_EXIF, EXIF_TAG_EXIF_VERSION, EXIF_FORMAT_UNDEFINED, exif_version);
+    return true;
+}
+
+bool ExifUtilsImpl::setMake(const std::string& make) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_MAKE, EXIF_FORMAT_ASCII, make);
+    return true;
+}
+
+bool ExifUtilsImpl::setModel(const std::string& model) {
+    SET_STRING(EXIF_IFD_0, EXIF_TAG_MODEL, EXIF_FORMAT_ASCII, model);
+    return true;
+}
+
+void ExifUtilsImpl::reset() {
+    destroyApp1();
+    if (exif_data_) {
+        /*
+         * Since we decided to ignore the original APP1, we are sure that there is
+         * no thumbnail allocated by libexif. |exif_data_->data| is actually
+         * allocated by JpegCompressor. sets |exif_data_->data| to nullptr to
+         * prevent exif_data_unref() destroy it incorrectly.
+         */
+        exif_data_->data = nullptr;
+        exif_data_->size = 0;
+        exif_data_unref(exif_data_);
+        exif_data_ = nullptr;
+    }
+}
+
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addVariableLengthEntry(ExifIfd ifd,
+                                                                 ExifTag tag,
+                                                                 ExifFormat format,
+                                                                 uint64_t components,
+                                                                 unsigned int size) {
+    // Remove old entry if exists.
+    exif_content_remove_entry(exif_data_->ifd[ifd],
+                              exif_content_get_entry(exif_data_->ifd[ifd], tag));
+    ExifMem* mem = exif_mem_new_default();
+    if (!mem) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        return nullptr;
+    }
+    std::unique_ptr<ExifEntry> entry(exif_entry_new_mem(mem));
+    if (!entry) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        exif_mem_unref(mem);
+        return nullptr;
+    }
+    void* tmpBuffer = exif_mem_alloc(mem, size);
+    if (!tmpBuffer) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        exif_mem_unref(mem);
+        return nullptr;
+    }
+
+    entry->data = static_cast<unsigned char*>(tmpBuffer);
+    entry->tag = tag;
+    entry->format = format;
+    entry->components = components;
+    entry->size = size;
+
+    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
+    exif_mem_unref(mem);
+
+    return entry;
+}
+
+std::unique_ptr<ExifEntry> ExifUtilsImpl::addEntry(ExifIfd ifd, ExifTag tag) {
+    std::unique_ptr<ExifEntry> entry(exif_content_get_entry(exif_data_->ifd[ifd], tag));
+    if (entry) {
+        // exif_content_get_entry() won't ref the entry, so we ref here.
+        exif_entry_ref(entry.get());
+        return entry;
+    }
+    entry.reset(exif_entry_new());
+    if (!entry) {
+        ALOGE("%s: Allocate memory for exif entry failed", __FUNCTION__);
+        return nullptr;
+    }
+    entry->tag = tag;
+    exif_content_add_entry(exif_data_->ifd[ifd], entry.get());
+    exif_entry_initialize(entry.get(), tag);
+    return entry;
+}
+
+bool ExifUtilsImpl::setShort(ExifIfd ifd,
+                             ExifTag tag,
+                             uint16_t value,
+                             const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_short(entry->data, EXIF_BYTE_ORDER_INTEL, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setLong(ExifIfd ifd,
+                            ExifTag tag,
+                            uint32_t value,
+                            const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_long(entry->data, EXIF_BYTE_ORDER_INTEL, value);
+    return true;
+}
+
+bool ExifUtilsImpl::setRational(ExifIfd ifd,
+                                ExifTag tag,
+                                uint32_t numerator,
+                                uint32_t denominator,
+                                const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_rational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                        {numerator, denominator});
+    return true;
+}
+
+bool ExifUtilsImpl::setSRational(ExifIfd ifd,
+                                 ExifTag tag,
+                                 int32_t numerator,
+                                 int32_t denominator,
+                                 const std::string& msg) {
+    std::unique_ptr<ExifEntry> entry = addEntry(ifd, tag);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    exif_set_srational(entry->data, EXIF_BYTE_ORDER_INTEL,
+                                          {numerator, denominator});
+    return true;
+}
+
+bool ExifUtilsImpl::setString(ExifIfd ifd,
+                              ExifTag tag,
+                              ExifFormat format,
+                              const std::string& buffer,
+                              const std::string& msg) {
+    size_t entry_size = buffer.length();
+    // Since the exif format is undefined, NULL termination is not necessary.
+    if (format == EXIF_FORMAT_ASCII) {
+        entry_size++;
+    }
+    std::unique_ptr<ExifEntry> entry =
+            addVariableLengthEntry(ifd, tag, format, entry_size, entry_size);
+    if (!entry) {
+        ALOGE("%s: Adding '%s' entry failed", __FUNCTION__, msg.c_str());
+        return false;
+    }
+    memcpy(entry->data, buffer.c_str(), entry_size);
+    return true;
+}
+
+void ExifUtilsImpl::destroyApp1() {
+    /*
+     * Since there is no API to access ExifMem in ExifData->priv, we use free
+     * here, which is the default free function in libexif. See
+     * exif_data_save_data() for detail.
+     */
+    free(app1_buffer_);
+    app1_buffer_ = nullptr;
+    app1_length_ = 0;
+}
+
+bool ExifUtilsImpl::setFromMetadata(const CameraMetadata& metadata,
+                                    const size_t imageWidth,
+                                    const size_t imageHeight) {
+    // How precise the float-to-rational conversion for EXIF tags would be.
+    constexpr int kRationalPrecision = 10000;
+    if (!setImageWidth(imageWidth) ||
+            !setImageHeight(imageHeight)) {
+        ALOGE("%s: setting image resolution failed.", __FUNCTION__);
+        return false;
+    }
+
+    struct timespec tp;
+    struct tm time_info;
+    bool time_available = clock_gettime(CLOCK_REALTIME, &tp) != -1;
+    localtime_r(&tp.tv_sec, &time_info);
+    if (!setDateTime(time_info)) {
+        ALOGE("%s: setting data time failed.", __FUNCTION__);
+        return false;
+    }
+
+    float focal_length;
+    camera_metadata_ro_entry entry = metadata.find(ANDROID_LENS_FOCAL_LENGTH);
+    if (entry.count) {
+        focal_length = entry.data.f[0];
+    } else {
+        ALOGE("%s: Cannot find focal length in metadata.", __FUNCTION__);
+        return false;
+    }
+    if (!setFocalLength(
+                    static_cast<uint32_t>(focal_length * kRationalPrecision),
+                    kRationalPrecision)) {
+        ALOGE("%s: setting focal length failed.", __FUNCTION__);
+        return false;
+    }
+
+    if (metadata.exists(ANDROID_JPEG_GPS_COORDINATES)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_COORDINATES);
+        if (entry.count < 3) {
+            ALOGE("%s: Gps coordinates in metadata is not complete.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsLatitude(entry.data.d[0])) {
+            ALOGE("%s: setting gps latitude failed.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsLongitude(entry.data.d[1])) {
+            ALOGE("%s: setting gps longitude failed.", __FUNCTION__);
+            return false;
+        }
+        if (!setGpsAltitude(entry.data.d[2])) {
+            ALOGE("%s: setting gps altitude failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_JPEG_GPS_PROCESSING_METHOD)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_PROCESSING_METHOD);
+        std::string method_str(reinterpret_cast<const char*>(entry.data.u8));
+        if (!setGpsProcessingMethod(method_str)) {
+            ALOGE("%s: setting gps processing method failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (time_available && metadata.exists(ANDROID_JPEG_GPS_TIMESTAMP)) {
+        entry = metadata.find(ANDROID_JPEG_GPS_TIMESTAMP);
+        time_t timestamp = static_cast<time_t>(entry.data.i64[0]);
+        if (gmtime_r(&timestamp, &time_info)) {
+            if (!setGpsTimestamp(time_info)) {
+                ALOGE("%s: setting gps timestamp failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Time tranformation failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_JPEG_ORIENTATION)) {
+        entry = metadata.find(ANDROID_JPEG_ORIENTATION);
+        if (!setOrientation(entry.data.i32[0])) {
+            ALOGE("%s: setting orientation failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
+        entry = metadata.find(ANDROID_SENSOR_EXPOSURE_TIME);
+        // int64_t of nanoseconds
+        if (!setExposureTime(entry.data.i64[0],1000000000u)) {
+            ALOGE("%s: setting exposure time failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_LENS_APERTURE)) {
+        const int kAperturePrecision = 10000;
+        entry = metadata.find(ANDROID_LENS_APERTURE);
+        if (!setFNumber(entry.data.f[0] * kAperturePrecision,
+                                                      kAperturePrecision)) {
+            ALOGE("%s: setting F number failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_FLASH_INFO_AVAILABLE)) {
+        entry = metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+        if (entry.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_FALSE) {
+            const uint32_t kNoFlashFunction = 0x20;
+            if (!setFlash(kNoFlashFunction)) {
+                ALOGE("%s: setting flash failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Unsupported flash info: %d",__FUNCTION__, entry.data.u8[0]);
+            return false;
+        }
+    }
+
+    if (metadata.exists(ANDROID_CONTROL_AWB_MODE)) {
+        entry = metadata.find(ANDROID_CONTROL_AWB_MODE);
+        if (entry.data.u8[0] == ANDROID_CONTROL_AWB_MODE_AUTO) {
+            const uint16_t kAutoWhiteBalance = 0;
+            if (!setWhiteBalance(kAutoWhiteBalance)) {
+                ALOGE("%s: setting white balance failed.", __FUNCTION__);
+                return false;
+            }
+        } else {
+            ALOGE("%s: Unsupported awb mode: %d", __FUNCTION__, entry.data.u8[0]);
+            return false;
+        }
+    }
+
+    if (time_available) {
+        char str[4];
+        if (snprintf(str, sizeof(str), "%03ld", tp.tv_nsec / 1000000) < 0) {
+            ALOGE("%s: Subsec is invalid: %ld", __FUNCTION__, tp.tv_nsec);
+            return false;
+        }
+        if (!setSubsecTime(std::string(str))) {
+            ALOGE("%s: setting subsec time failed.", __FUNCTION__);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index fd8b943..21706a8 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -134,6 +134,97 @@
     }
 }
 
+void* HandleImporter::lock(
+        buffer_handle_t& buf, uint64_t cpuUsage, size_t size) {
+    Mutex::Autolock lock(mLock);
+    void *ret = 0;
+    IMapper::Rect accessRegion { 0, 0, static_cast<int>(size), 1 };
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapper == nullptr) {
+        ALOGE("%s: mMapper is null!", __FUNCTION__);
+        return ret;
+    }
+
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+            [&](const auto& tmpError, const auto& tmpPtr) {
+                if (tmpError == MapperError::NONE) {
+                    ret = tmpPtr;
+                } else {
+                    ALOGE("%s: failed to lock error %d!",
+                          __FUNCTION__, tmpError);
+                }
+           });
+
+    ALOGV("%s: ptr %p size: %zu", __FUNCTION__, ret, size);
+    return ret;
+}
+
+
+YCbCrLayout HandleImporter::lockYCbCr(
+        buffer_handle_t& buf, uint64_t cpuUsage,
+        const IMapper::Rect& accessRegion) {
+    Mutex::Autolock lock(mLock);
+    YCbCrLayout layout = {};
+
+    if (!mInitialized) {
+        initializeLocked();
+    }
+
+    if (mMapper == nullptr) {
+        ALOGE("%s: mMapper is null!", __FUNCTION__);
+        return layout;
+    }
+
+    hidl_handle acquireFenceHandle;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+            [&](const auto& tmpError, const auto& tmpLayout) {
+                if (tmpError == MapperError::NONE) {
+                    layout = tmpLayout;
+                } else {
+                    ALOGE("%s: failed to lockYCbCr error %d!", __FUNCTION__, tmpError);
+                }
+           });
+
+    ALOGV("%s: layout y %p cb %p cr %p y_str %d c_str %d c_step %d",
+            __FUNCTION__, layout.y, layout.cb, layout.cr,
+            layout.yStride, layout.cStride, layout.chromaStep);
+    return layout;
+}
+
+int HandleImporter::unlock(buffer_handle_t& buf) {
+    int releaseFence = -1;
+    auto buffer = const_cast<native_handle_t*>(buf);
+    mMapper->unlock(
+        buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+            if (tmpError == MapperError::NONE) {
+                auto fenceHandle = tmpReleaseFence.getNativeHandle();
+                if (fenceHandle) {
+                    if (fenceHandle->numInts != 0 || fenceHandle->numFds != 1) {
+                        ALOGE("%s: bad release fence numInts %d numFds %d",
+                                __FUNCTION__, fenceHandle->numInts, fenceHandle->numFds);
+                        return;
+                    }
+                    releaseFence = dup(fenceHandle->data[0]);
+                    if (releaseFence <= 0) {
+                        ALOGE("%s: bad release fence FD %d",
+                                __FUNCTION__, releaseFence);
+                    }
+                }
+            } else {
+                ALOGE("%s: failed to unlock error %d!", __FUNCTION__, tmpError);
+            }
+        });
+
+    return releaseFence;
+}
+
 } // namespace helper
 } // namespace V1_0
 } // namespace common
diff --git a/camera/common/1.0/default/include/Exif.h b/camera/common/1.0/default/include/Exif.h
new file mode 100644
index 0000000..dc31679
--- /dev/null
+++ b/camera/common/1.0/default/include/Exif.h
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
+#define ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
+
+#include "CameraMetadata.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+
+// This is based on the original ChromeOS ARC implementation of a V4L2 HAL
+
+// ExifUtils can generate APP1 segment with tags which caller set. ExifUtils can
+// also add a thumbnail in the APP1 segment if thumbnail size is specified.
+// ExifUtils can be reused with different images by calling initialize().
+//
+// Example of using this class :
+//  std::unique_ptr<ExifUtils> utils(ExifUtils::Create());
+//  utils->initialize();
+//  ...
+//  // Call ExifUtils functions to set Exif tags.
+//  ...
+//  utils->GenerateApp1(thumbnail_buffer, thumbnail_size);
+//  unsigned int app1Length = utils->GetApp1Length();
+//  uint8_t* app1Buffer = new uint8_t[app1Length];
+//  memcpy(app1Buffer, utils->GetApp1Buffer(), app1Length);
+class ExifUtils {
+
+ public:
+    virtual ~ExifUtils();
+
+    static ExifUtils* create();
+
+    // Initialize() can be called multiple times. The setting of Exif tags will be
+    // cleared.
+    virtual bool initialize() = 0;
+
+    // Set all known fields from a metadata structure
+    virtual bool setFromMetadata(const CameraMetadata& metadata,
+                                 const size_t imageWidth,
+                                 const size_t imageHeight) = 0;
+
+    // Sets the len aperture.
+    // Returns false if memory allocation fails.
+    virtual bool setAperture(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the value of brightness.
+    // Returns false if memory allocation fails.
+    virtual bool setBrightness(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the color space.
+    // Returns false if memory allocation fails.
+    virtual bool setColorSpace(uint16_t color_space) = 0;
+
+    // Sets the information to compressed data.
+    // Returns false if memory allocation fails.
+    virtual bool setComponentsConfiguration(const std::string& components_configuration) = 0;
+
+    // Sets the compression scheme used for the image data.
+    // Returns false if memory allocation fails.
+    virtual bool setCompression(uint16_t compression) = 0;
+
+    // Sets image contrast.
+    // Returns false if memory allocation fails.
+    virtual bool setContrast(uint16_t contrast) = 0;
+
+    // Sets the date and time of image last modified. It takes local time. The
+    // name of the tag is DateTime in IFD0.
+    // Returns false if memory allocation fails.
+    virtual bool setDateTime(const struct tm& t) = 0;
+
+    // Sets the image description.
+    // Returns false if memory allocation fails.
+    virtual bool setDescription(const std::string& description) = 0;
+
+    // Sets the digital zoom ratio. If the numerator is 0, it means digital zoom
+    // was not used.
+    // Returns false if memory allocation fails.
+    virtual bool setDigitalZoomRatio(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the exposure bias.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureBias(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the exposure mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureMode(uint16_t exposure_mode) = 0;
+
+    // Sets the program used by the camera to set exposure when the picture is
+    // taken.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureProgram(uint16_t exposure_program) = 0;
+
+    // Sets the exposure time, given in seconds.
+    // Returns false if memory allocation fails.
+    virtual bool setExposureTime(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the status of flash.
+    // Returns false if memory allocation fails.
+    virtual bool setFlash(uint16_t flash) = 0;
+
+    // Sets the F number.
+    // Returns false if memory allocation fails.
+    virtual bool setFNumber(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the focal length of lens used to take the image in millimeters.
+    // Returns false if memory allocation fails.
+    virtual bool setFocalLength(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the degree of overall image gain adjustment.
+    // Returns false if memory allocation fails.
+    virtual bool setGainControl(uint16_t gain_control) = 0;
+
+    // Sets the altitude in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsAltitude(double altitude) = 0;
+
+    // Sets the latitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLatitude(double latitude) = 0;
+
+    // Sets the longitude with degrees minutes seconds format.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsLongitude(double longitude) = 0;
+
+    // Sets GPS processing method.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsProcessingMethod(const std::string& method) = 0;
+
+    // Sets GPS date stamp and time stamp (atomic clock). It takes UTC time.
+    // Returns false if memory allocation fails.
+    virtual bool setGpsTimestamp(const struct tm& t) = 0;
+
+    // Sets the height (number of rows) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageHeight(uint32_t length) = 0;
+
+    // Sets the width (number of columns) of main image.
+    // Returns false if memory allocation fails.
+    virtual bool setImageWidth(uint32_t width) = 0;
+
+    // Sets the ISO speed.
+    // Returns false if memory allocation fails.
+    virtual bool setIsoSpeedRating(uint16_t iso_speed_ratings) = 0;
+
+    // Sets the kind of light source.
+    // Returns false if memory allocation fails.
+    virtual bool setLightSource(uint16_t light_source) = 0;
+
+    // Sets the smallest F number of the lens.
+    // Returns false if memory allocation fails.
+    virtual bool setMaxAperture(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the metering mode.
+    // Returns false if memory allocation fails.
+    virtual bool setMeteringMode(uint16_t metering_mode) = 0;
+
+    // Sets image orientation.
+    // Returns false if memory allocation fails.
+    virtual bool setOrientation(uint16_t orientation) = 0;
+
+    // Sets the unit for measuring XResolution and YResolution.
+    // Returns false if memory allocation fails.
+    virtual bool setResolutionUnit(uint16_t resolution_unit) = 0;
+
+    // Sets image saturation.
+    // Returns false if memory allocation fails.
+    virtual bool setSaturation(uint16_t saturation) = 0;
+
+    // Sets the type of scene that was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setSceneCaptureType(uint16_t type) = 0;
+
+    // Sets image sharpness.
+    // Returns false if memory allocation fails.
+    virtual bool setSharpness(uint16_t sharpness) = 0;
+
+    // Sets the shutter speed.
+    // Returns false if memory allocation fails.
+    virtual bool setShutterSpeed(int32_t numerator, int32_t denominator) = 0;
+
+    // Sets the distance to the subject, given in meters.
+    // Returns false if memory allocation fails.
+    virtual bool setSubjectDistance(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the fractions of seconds for the <DateTime> tag.
+    // Returns false if memory allocation fails.
+    virtual bool setSubsecTime(const std::string& subsec_time) = 0;
+
+    // Sets the white balance mode set when the image was shot.
+    // Returns false if memory allocation fails.
+    virtual bool setWhiteBalance(uint16_t white_balance) = 0;
+
+    // Sets the number of pixels per resolution unit in the image width.
+    // Returns false if memory allocation fails.
+    virtual bool setXResolution(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the position of chrominance components in relation to the luminance
+    // component.
+    // Returns false if memory allocation fails.
+    virtual bool setYCbCrPositioning(uint16_t ycbcr_positioning) = 0;
+
+    // Sets the number of pixels per resolution unit in the image length.
+    // Returns false if memory allocation fails.
+    virtual bool setYResolution(uint32_t numerator, uint32_t denominator) = 0;
+
+    // Sets the manufacturer of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setMake(const std::string& make) = 0;
+
+    // Sets the model number of camera.
+    // Returns false if memory allocation fails.
+    virtual bool setModel(const std::string& model) = 0;
+
+    // Generates APP1 segment.
+    // Returns false if generating APP1 segment fails.
+    virtual bool generateApp1(const void* thumbnail_buffer, uint32_t size) = 0;
+
+    // Gets buffer of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual const uint8_t* getApp1Buffer() = 0;
+
+    // Gets length of APP1 segment. This method must be called only after calling
+    // GenerateAPP1().
+    virtual unsigned int getApp1Length() = 0;
+};
+
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+
+#endif  // ANDROID_HARDWARE_INTERFACES_CAMERA_COMMON_1_0_EXIF_H
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
index e47397c..f9cd9fb 100644
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -22,6 +22,7 @@
 #include <cutils/native_handle.h>
 
 using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
 
 namespace android {
 namespace hardware {
@@ -43,6 +44,15 @@
     bool importFence(const native_handle_t* handle, int& fd) const;
     void closeFence(int fd) const;
 
+    // Assume caller has done waiting for acquire fences
+    void* lock(buffer_handle_t& buf, uint64_t cpuUsage, size_t size);
+
+    // Assume caller has done waiting for acquire fences
+    YCbCrLayout lockYCbCr(buffer_handle_t& buf, uint64_t cpuUsage,
+                          const IMapper::Rect& accessRegion);
+
+    int unlock(buffer_handle_t& buf); // returns release fence
+
 private:
     void initializeLocked();
     void cleanup();
@@ -60,4 +70,4 @@
 } // namespace hardware
 } // namespace android
 
-#endif // CAMERA_COMMON_1_0_HANDLEIMPORTED_H
\ No newline at end of file
+#endif // CAMERA_COMMON_1_0_HANDLEIMPORTED_H
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
index d6a04bc..975fb01 100644
--- a/camera/device/3.2/default/CameraDeviceSession.cpp
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -333,11 +333,10 @@
     mResultMetadataQueue = q;
 }
 
-void CameraDeviceSession::ResultBatcher::registerBatch(
-        const hidl_vec<CaptureRequest>& requests) {
+void CameraDeviceSession::ResultBatcher::registerBatch(uint32_t frameNumber, uint32_t batchSize) {
     auto batch = std::make_shared<InflightBatch>();
-    batch->mFirstFrame = requests[0].frameNumber;
-    batch->mBatchSize = requests.size();
+    batch->mFirstFrame = frameNumber;
+    batch->mBatchSize = batchSize;
     batch->mLastFrame = batch->mFirstFrame + batch->mBatchSize - 1;
     batch->mNumPartialResults = mNumPartialResults;
     for (int id : mStreamsToBatch) {
@@ -739,8 +738,14 @@
 // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow.
 Return<void> CameraDeviceSession::constructDefaultRequestSettings(
         RequestTemplate type, ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb)  {
-    Status status = initStatus();
     CameraMetadata outMetadata;
+    Status status = constructDefaultRequestSettingsRaw( (int) type, &outMetadata);
+    _hidl_cb(status, outMetadata);
+    return Void();
+}
+
+Status CameraDeviceSession::constructDefaultRequestSettingsRaw(int type, CameraMetadata *outMetadata) {
+    Status status = initStatus();
     const camera_metadata_t *rawRequest;
     if (status == Status::OK) {
         ATRACE_BEGIN("camera3->construct_default_request_settings");
@@ -762,15 +767,14 @@
                         defaultBoost, 1);
                 const camera_metadata_t *metaBuffer =
                         mOverridenRequest.getAndLock();
-                convertToHidl(metaBuffer, &outMetadata);
+                convertToHidl(metaBuffer, outMetadata);
                 mOverridenRequest.unlock(metaBuffer);
             } else {
-                convertToHidl(rawRequest, &outMetadata);
+                convertToHidl(rawRequest, outMetadata);
             }
         }
     }
-    _hidl_cb(status, outMetadata);
-    return Void();
+    return status;
 }
 
 /**
@@ -803,6 +807,89 @@
    return dataSpace;
 }
 
+bool CameraDeviceSession::preProcessConfigurationLocked(
+        const StreamConfiguration& requestedConfiguration,
+        camera3_stream_configuration_t *stream_list /*out*/,
+        hidl_vec<camera3_stream_t*> *streams /*out*/) {
+
+    if ((stream_list == nullptr) || (streams == nullptr)) {
+        return false;
+    }
+
+    stream_list->operation_mode = (uint32_t) requestedConfiguration.operationMode;
+    stream_list->num_streams = requestedConfiguration.streams.size();
+    streams->resize(stream_list->num_streams);
+    stream_list->streams = streams->data();
+
+    for (uint32_t i = 0; i < stream_list->num_streams; i++) {
+        int id = requestedConfiguration.streams[i].id;
+
+        if (mStreamMap.count(id) == 0) {
+            Camera3Stream stream;
+            convertFromHidl(requestedConfiguration.streams[i], &stream);
+            mStreamMap[id] = stream;
+            mStreamMap[id].data_space = mapToLegacyDataspace(
+                    mStreamMap[id].data_space);
+            mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
+        } else {
+            // width/height/format must not change, but usage/rotation might need to change
+            if (mStreamMap[id].stream_type !=
+                    (int) requestedConfiguration.streams[i].streamType ||
+                    mStreamMap[id].width != requestedConfiguration.streams[i].width ||
+                    mStreamMap[id].height != requestedConfiguration.streams[i].height ||
+                    mStreamMap[id].format != (int) requestedConfiguration.streams[i].format ||
+                    mStreamMap[id].data_space !=
+                            mapToLegacyDataspace( static_cast<android_dataspace_t> (
+                                    requestedConfiguration.streams[i].dataSpace))) {
+                ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
+                return false;
+            }
+            mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation;
+            mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage;
+        }
+        (*streams)[i] = &mStreamMap[id];
+    }
+
+    return true;
+}
+
+void CameraDeviceSession::postProcessConfigurationLocked(
+        const StreamConfiguration& requestedConfiguration) {
+    // delete unused streams, note we do this after adding new streams to ensure new stream
+    // will not have the same address as deleted stream, and HAL has a chance to reference
+    // the to be deleted stream in configure_streams call
+    for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+        int id = it->first;
+        bool found = false;
+        for (const auto& stream : requestedConfiguration.streams) {
+            if (id == stream.id) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            // Unmap all buffers of deleted stream
+            // in case the configuration call succeeds and HAL
+            // is able to release the corresponding resources too.
+            cleanupBuffersLocked(id);
+            it = mStreamMap.erase(it);
+        } else {
+            ++it;
+        }
+    }
+
+    // Track video streams
+    mVideoStreamIds.clear();
+    for (const auto& stream : requestedConfiguration.streams) {
+        if (stream.streamType == StreamType::OUTPUT &&
+            stream.usage &
+                graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) {
+            mVideoStreamIds.push_back(stream.id);
+        }
+    }
+    mResultBatcher.setBatchedStreams(mVideoStreamIds);
+}
+
 Return<void> CameraDeviceSession::configureStreams(
         const StreamConfiguration& requestedConfiguration,
         ICameraDeviceSession::configureStreams_cb _hidl_cb)  {
@@ -840,42 +927,11 @@
         return Void();
     }
 
-    camera3_stream_configuration_t stream_list;
+    camera3_stream_configuration_t stream_list{};
     hidl_vec<camera3_stream_t*> streams;
-
-    stream_list.operation_mode = (uint32_t) requestedConfiguration.operationMode;
-    stream_list.num_streams = requestedConfiguration.streams.size();
-    streams.resize(stream_list.num_streams);
-    stream_list.streams = streams.data();
-
-    for (uint32_t i = 0; i < stream_list.num_streams; i++) {
-        int id = requestedConfiguration.streams[i].id;
-
-        if (mStreamMap.count(id) == 0) {
-            Camera3Stream stream;
-            convertFromHidl(requestedConfiguration.streams[i], &stream);
-            mStreamMap[id] = stream;
-            mStreamMap[id].data_space = mapToLegacyDataspace(
-                    mStreamMap[id].data_space);
-            mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
-        } else {
-            // width/height/format must not change, but usage/rotation might need to change
-            if (mStreamMap[id].stream_type !=
-                    (int) requestedConfiguration.streams[i].streamType ||
-                    mStreamMap[id].width != requestedConfiguration.streams[i].width ||
-                    mStreamMap[id].height != requestedConfiguration.streams[i].height ||
-                    mStreamMap[id].format != (int) requestedConfiguration.streams[i].format ||
-                    mStreamMap[id].data_space !=
-                            mapToLegacyDataspace( static_cast<android_dataspace_t> (
-                                    requestedConfiguration.streams[i].dataSpace))) {
-                ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
-                _hidl_cb(Status::INTERNAL_ERROR, outStreams);
-                return Void();
-            }
-            mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation;
-            mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage;
-        }
-        streams[i] = &mStreamMap[id];
+    if (!preProcessConfigurationLocked(requestedConfiguration, &stream_list, &streams)) {
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
     }
 
     ATRACE_BEGIN("camera3->configure_streams");
@@ -885,39 +941,7 @@
     // In case Hal returns error most likely it was not able to release
     // the corresponding resources of the deleted streams.
     if (ret == OK) {
-        // delete unused streams, note we do this after adding new streams to ensure new stream
-        // will not have the same address as deleted stream, and HAL has a chance to reference
-        // the to be deleted stream in configure_streams call
-        for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
-            int id = it->first;
-            bool found = false;
-            for (const auto& stream : requestedConfiguration.streams) {
-                if (id == stream.id) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                // Unmap all buffers of deleted stream
-                // in case the configuration call succeeds and HAL
-                // is able to release the corresponding resources too.
-                cleanupBuffersLocked(id);
-                it = mStreamMap.erase(it);
-            } else {
-                ++it;
-            }
-        }
-
-        // Track video streams
-        mVideoStreamIds.clear();
-        for (const auto& stream : requestedConfiguration.streams) {
-            if (stream.streamType == StreamType::OUTPUT &&
-                stream.usage &
-                    graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) {
-                mVideoStreamIds.push_back(stream.id);
-            }
-        }
-        mResultBatcher.setBatchedStreams(mVideoStreamIds);
+        postProcessConfigurationLocked(requestedConfiguration);
     }
 
     if (ret == -EINVAL) {
@@ -990,7 +1014,7 @@
     }
 
     if (s == Status::OK && requests.size() > 1) {
-        mResultBatcher.registerBatch(requests);
+        mResultBatcher.registerBatch(requests[0].frameNumber, requests.size());
     }
 
     _hidl_cb(s, numRequestProcessed);
@@ -1091,6 +1115,7 @@
             halRequest.settings = settingsOverride.getAndLock();
         }
     }
+    halRequest.num_physcam_settings = 0;
 
     ATRACE_ASYNC_BEGIN("frame capture", request.frameNumber);
     ATRACE_BEGIN("camera3->process_capture_request");
@@ -1173,26 +1198,19 @@
     return Void();
 }
 
-/**
- * Static callback forwarding methods from HAL to instance
- */
-void CameraDeviceSession::sProcessCaptureResult(
-        const camera3_callback_ops *cb,
-        const camera3_capture_result *hal_result) {
-    CameraDeviceSession *d =
-            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
-
+void CameraDeviceSession::constructCaptureResult(CaptureResult& result,
+                                                 const camera3_capture_result *hal_result) {
     uint32_t frameNumber = hal_result->frame_number;
     bool hasInputBuf = (hal_result->input_buffer != nullptr);
     size_t numOutputBufs = hal_result->num_output_buffers;
     size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
     if (numBufs > 0) {
-        Mutex::Autolock _l(d->mInflightLock);
+        Mutex::Autolock _l(mInflightLock);
         if (hasInputBuf) {
             int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
             // validate if buffer is inflight
             auto key = std::make_pair(streamId, frameNumber);
-            if (d->mInflightBuffers.count(key) != 1) {
+            if (mInflightBuffers.count(key) != 1) {
                 ALOGE("%s: input buffer for stream %d frame %d is not inflight!",
                         __FUNCTION__, streamId, frameNumber);
                 return;
@@ -1203,7 +1221,7 @@
             int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
             // validate if buffer is inflight
             auto key = std::make_pair(streamId, frameNumber);
-            if (d->mInflightBuffers.count(key) != 1) {
+            if (mInflightBuffers.count(key) != 1) {
                 ALOGE("%s: output buffer for stream %d frame %d is not inflight!",
                         __FUNCTION__, streamId, frameNumber);
                 return;
@@ -1212,64 +1230,63 @@
     }
     // We don't need to validate/import fences here since we will be passing them to camera service
     // within the scope of this function
-    CaptureResult result;
     result.frameNumber = frameNumber;
     result.fmqResultSize = 0;
     result.partialResult = hal_result->partial_result;
     convertToHidl(hal_result->result, &result.result);
     if (nullptr != hal_result->result) {
         bool resultOverriden = false;
-        Mutex::Autolock _l(d->mInflightLock);
+        Mutex::Autolock _l(mInflightLock);
 
         // Derive some new keys for backward compatibility
-        if (d->mDerivePostRawSensKey) {
+        if (mDerivePostRawSensKey) {
             camera_metadata_ro_entry entry;
             if (find_camera_metadata_ro_entry(hal_result->result,
                     ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST, &entry) == 0) {
-                d->mInflightRawBoostPresent[frameNumber] = true;
+                mInflightRawBoostPresent[frameNumber] = true;
             } else {
-                auto entry = d->mInflightRawBoostPresent.find(frameNumber);
-                if (d->mInflightRawBoostPresent.end() == entry) {
-                    d->mInflightRawBoostPresent[frameNumber] = false;
+                auto entry = mInflightRawBoostPresent.find(frameNumber);
+                if (mInflightRawBoostPresent.end() == entry) {
+                    mInflightRawBoostPresent[frameNumber] = false;
                 }
             }
 
-            if ((hal_result->partial_result == d->mNumPartialResults)) {
-                if (!d->mInflightRawBoostPresent[frameNumber]) {
+            if ((hal_result->partial_result == mNumPartialResults)) {
+                if (!mInflightRawBoostPresent[frameNumber]) {
                     if (!resultOverriden) {
-                        d->mOverridenResult.clear();
-                        d->mOverridenResult.append(hal_result->result);
+                        mOverridenResult.clear();
+                        mOverridenResult.append(hal_result->result);
                         resultOverriden = true;
                     }
                     int32_t defaultBoost[1] = {100};
-                    d->mOverridenResult.update(
+                    mOverridenResult.update(
                             ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST,
                             defaultBoost, 1);
                 }
 
-                d->mInflightRawBoostPresent.erase(frameNumber);
+                mInflightRawBoostPresent.erase(frameNumber);
             }
         }
 
-        auto entry = d->mInflightAETriggerOverrides.find(frameNumber);
-        if (d->mInflightAETriggerOverrides.end() != entry) {
+        auto entry = mInflightAETriggerOverrides.find(frameNumber);
+        if (mInflightAETriggerOverrides.end() != entry) {
             if (!resultOverriden) {
-                d->mOverridenResult.clear();
-                d->mOverridenResult.append(hal_result->result);
+                mOverridenResult.clear();
+                mOverridenResult.append(hal_result->result);
                 resultOverriden = true;
             }
-            d->overrideResultForPrecaptureCancelLocked(entry->second,
-                    &d->mOverridenResult);
-            if (hal_result->partial_result == d->mNumPartialResults) {
-                d->mInflightAETriggerOverrides.erase(frameNumber);
+            overrideResultForPrecaptureCancelLocked(entry->second,
+                    &mOverridenResult);
+            if (hal_result->partial_result == mNumPartialResults) {
+                mInflightAETriggerOverrides.erase(frameNumber);
             }
         }
 
         if (resultOverriden) {
             const camera_metadata_t *metaBuffer =
-                    d->mOverridenResult.getAndLock();
+                    mOverridenResult.getAndLock();
             convertToHidl(metaBuffer, &result.result);
-            d->mOverridenResult.unlock(metaBuffer);
+            mOverridenResult.unlock(metaBuffer);
         }
     }
     if (hasInputBuf) {
@@ -1310,24 +1327,38 @@
     // configure_streams right after the processCaptureResult call so we need to finish
     // updating inflight queues first
     if (numBufs > 0) {
-        Mutex::Autolock _l(d->mInflightLock);
+        Mutex::Autolock _l(mInflightLock);
         if (hasInputBuf) {
             int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
             auto key = std::make_pair(streamId, frameNumber);
-            d->mInflightBuffers.erase(key);
+            mInflightBuffers.erase(key);
         }
 
         for (size_t i = 0; i < numOutputBufs; i++) {
             int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
             auto key = std::make_pair(streamId, frameNumber);
-            d->mInflightBuffers.erase(key);
+            mInflightBuffers.erase(key);
         }
 
-        if (d->mInflightBuffers.empty()) {
+        if (mInflightBuffers.empty()) {
             ALOGV("%s: inflight buffer queue is now empty!", __FUNCTION__);
         }
     }
 
+}
+
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+void CameraDeviceSession::sProcessCaptureResult(
+        const camera3_callback_ops *cb,
+        const camera3_capture_result *hal_result) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+    CaptureResult result;
+    d->constructCaptureResult(result, hal_result);
+
     d->mResultBatcher.processCaptureResult(result);
 }
 
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h
index 69e2e2c..61db671 100644
--- a/camera/device/3.2/default/CameraDeviceSession.h
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -112,6 +112,14 @@
     Return<Status> flush();
     Return<void> close();
 
+    // Helper methods
+    Status constructDefaultRequestSettingsRaw(int type, CameraMetadata *outMetadata);
+
+    bool preProcessConfigurationLocked(const StreamConfiguration& requestedConfiguration,
+            camera3_stream_configuration_t *stream_list /*out*/,
+            hidl_vec<camera3_stream_t*> *streams /*out*/);
+    void postProcessConfigurationLocked(const StreamConfiguration& requestedConfiguration);
+
 protected:
 
     // protecting mClosed/mDisconnected/mInitFail
@@ -178,11 +186,11 @@
         void setBatchedStreams(const std::vector<int>& streamsToBatch);
         void setResultMetadataQueue(std::shared_ptr<ResultMetadataQueue> q);
 
-        void registerBatch(const hidl_vec<CaptureRequest>& requests);
+        void registerBatch(uint32_t frameNumber, uint32_t batchSize);
         void notify(NotifyMsg& msg);
         void processCaptureResult(CaptureResult& result);
 
-    private:
+    protected:
         struct InflightBatch {
             // Protect access to entire struct. Acquire this lock before read/write any data or
             // calling any methods. processCaptureResult and notify will compete for this lock
@@ -227,7 +235,6 @@
             bool mRemoved = false;
         };
 
-        static const int NOT_BATCHED = -1;
 
         // Get the batch index and pointer to InflightBatch (nullptrt if the frame is not batched)
         // Caller must acquire the InflightBatch::mLock before accessing the InflightBatch
@@ -237,6 +244,16 @@
         // This method will hold ResultBatcher::mLock briefly
         std::pair<int, std::shared_ptr<InflightBatch>> getBatch(uint32_t frameNumber);
 
+        static const int NOT_BATCHED = -1;
+
+        // move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native
+        // handle
+        void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst);
+        void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst);
+
+        void sendBatchMetadataLocked(
+                std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx);
+
         // Check if the first batch in mInflightBatches is ready to be removed, and remove it if so
         // This method will hold ResultBatcher::mLock briefly
         void checkAndRemoveFirstBatch();
@@ -249,9 +266,7 @@
         // send buffers for specified streams
         void sendBatchBuffersLocked(
                 std::shared_ptr<InflightBatch> batch, const std::vector<int>& streams);
-        void sendBatchMetadataLocked(
-                std::shared_ptr<InflightBatch> batch, uint32_t lastPartialResultIdx);
-        // End of sendXXXX methods
+       // End of sendXXXX methods
 
         // helper methods
         void freeReleaseFences(hidl_vec<CaptureResult>&);
@@ -259,11 +274,6 @@
         void processOneCaptureResult(CaptureResult& result);
         void invokeProcessCaptureResultCallback(hidl_vec<CaptureResult> &results, bool tryWriteFmq);
 
-        // move/push function avoids "hidl_handle& operator=(hidl_handle&)", which clones native
-        // handle
-        void moveStreamBuffer(StreamBuffer&& src, StreamBuffer& dst);
-        void pushStreamBuffer(StreamBuffer&& src, std::vector<StreamBuffer>& dst);
-
         // Protect access to mInflightBatches, mNumPartialResults and mStreamsToBatch
         // processCaptureRequest, processCaptureResult, notify will compete for this lock
         // Do NOT issue HIDL IPCs while holding this lock (except when HAL reports error)
@@ -317,6 +327,8 @@
     static callbacks_process_capture_result_t sProcessCaptureResult;
     static callbacks_notify_t sNotify;
 
+    void constructCaptureResult(CaptureResult& result,
+                                const camera3_capture_result *hal_result);
 private:
 
     struct TrampolineSessionInterface_3_2 : public ICameraDeviceSession {
diff --git a/camera/device/3.3/default/CameraDeviceSession.cpp b/camera/device/3.3/default/CameraDeviceSession.cpp
index f877895..d36e9ed 100644
--- a/camera/device/3.3/default/CameraDeviceSession.cpp
+++ b/camera/device/3.3/default/CameraDeviceSession.cpp
@@ -77,42 +77,11 @@
         return Void();
     }
 
-    camera3_stream_configuration_t stream_list;
+    camera3_stream_configuration_t stream_list{};
     hidl_vec<camera3_stream_t*> streams;
-
-    stream_list.operation_mode = (uint32_t) requestedConfiguration.operationMode;
-    stream_list.num_streams = requestedConfiguration.streams.size();
-    streams.resize(stream_list.num_streams);
-    stream_list.streams = streams.data();
-
-    for (uint32_t i = 0; i < stream_list.num_streams; i++) {
-        int id = requestedConfiguration.streams[i].id;
-
-        if (mStreamMap.count(id) == 0) {
-            Camera3Stream stream;
-            V3_2::implementation::convertFromHidl(requestedConfiguration.streams[i], &stream);
-            mStreamMap[id] = stream;
-            mStreamMap[id].data_space = mapToLegacyDataspace(
-                    mStreamMap[id].data_space);
-            mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
-        } else {
-            // width/height/format must not change, but usage/rotation might need to change
-            if (mStreamMap[id].stream_type !=
-                    (int) requestedConfiguration.streams[i].streamType ||
-                    mStreamMap[id].width != requestedConfiguration.streams[i].width ||
-                    mStreamMap[id].height != requestedConfiguration.streams[i].height ||
-                    mStreamMap[id].format != (int) requestedConfiguration.streams[i].format ||
-                    mStreamMap[id].data_space !=
-                            mapToLegacyDataspace( static_cast<android_dataspace_t> (
-                                    requestedConfiguration.streams[i].dataSpace))) {
-                ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
-                _hidl_cb(Status::INTERNAL_ERROR, outStreams);
-                return Void();
-            }
-            mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation;
-            mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage;
-        }
-        streams[i] = &mStreamMap[id];
+    if (!preProcessConfigurationLocked(requestedConfiguration, &stream_list, &streams)) {
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
     }
 
     ATRACE_BEGIN("camera3->configure_streams");
@@ -122,39 +91,7 @@
     // In case Hal returns error most likely it was not able to release
     // the corresponding resources of the deleted streams.
     if (ret == OK) {
-        // delete unused streams, note we do this after adding new streams to ensure new stream
-        // will not have the same address as deleted stream, and HAL has a chance to reference
-        // the to be deleted stream in configure_streams call
-        for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
-            int id = it->first;
-            bool found = false;
-            for (const auto& stream : requestedConfiguration.streams) {
-                if (id == stream.id) {
-                    found = true;
-                    break;
-                }
-            }
-            if (!found) {
-                // Unmap all buffers of deleted stream
-                // in case the configuration call succeeds and HAL
-                // is able to release the corresponding resources too.
-                cleanupBuffersLocked(id);
-                it = mStreamMap.erase(it);
-            } else {
-                ++it;
-            }
-        }
-
-        // Track video streams
-        mVideoStreamIds.clear();
-        for (const auto& stream : requestedConfiguration.streams) {
-            if (stream.streamType == V3_2::StreamType::OUTPUT &&
-                stream.usage &
-                    graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) {
-                mVideoStreamIds.push_back(stream.id);
-            }
-        }
-        mResultBatcher.setBatchedStreams(mVideoStreamIds);
+        postProcessConfigurationLocked(requestedConfiguration);
     }
 
     if (ret == -EINVAL) {
diff --git a/camera/device/3.4/Android.bp b/camera/device/3.4/Android.bp
new file mode 100644
index 0000000..87acd25
--- /dev/null
+++ b/camera/device/3.4/Android.bp
@@ -0,0 +1,34 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.device@3.4",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ICameraDeviceCallback.hal",
+        "ICameraDeviceSession.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.common@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.graphics.common@1.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "CaptureRequest",
+        "CaptureResult",
+        "HalStream",
+        "HalStreamConfiguration",
+        "PhysicalCameraMetadata",
+        "PhysicalCameraSetting",
+        "RequestTemplate",
+        "Stream",
+        "StreamConfiguration",
+    ],
+    gen_java: false,
+}
+
diff --git a/camera/device/3.4/ICameraDeviceCallback.hal b/camera/device/3.4/ICameraDeviceCallback.hal
new file mode 100644
index 0000000..8ce8d4b
--- /dev/null
+++ b/camera/device/3.4/ICameraDeviceCallback.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.4;
+
+import @3.2::ICameraDeviceCallback;
+
+/**
+ *
+ * Callback methods for the HAL to call into the framework.
+ *
+ * These methods are used to return metadata and image buffers for a completed
+ * or failed captures, and to notify the framework of asynchronous events such
+ * as errors.
+ *
+ * The framework must not call back into the HAL from within these callbacks,
+ * and these calls must not block for extended periods.
+ *
+ */
+interface ICameraDeviceCallback extends @3.2::ICameraDeviceCallback {
+    /**
+     * processCaptureResult_3_4:
+     *
+     * Identical to @3.2::ICameraDeviceCallback.processCaptureResult, except
+     * that it takes a list of @3.4::CaptureResult, which could contain
+     * physical camera metadata for logical multi-camera.
+     *
+     */
+    processCaptureResult_3_4(vec<@3.4::CaptureResult> results);
+};
diff --git a/camera/device/3.4/ICameraDeviceSession.hal b/camera/device/3.4/ICameraDeviceSession.hal
new file mode 100644
index 0000000..7afcf94
--- /dev/null
+++ b/camera/device/3.4/ICameraDeviceSession.hal
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2017-2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.4;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.2::CameraMetadata;
+import @3.3::ICameraDeviceSession;
+import @3.3::HalStreamConfiguration;
+import @3.2::BufferCache;
+
+/**
+ * Camera device active session interface.
+ *
+ * Obtained via ICameraDevice::open(), this interface contains the methods to
+ * configure and request captures from an active camera device.
+ */
+interface ICameraDeviceSession extends @3.3::ICameraDeviceSession {
+
+    /**
+     * constructDefaultRequestSettings_3_4:
+     *
+     * Create capture settings for standard camera use cases. Supports the
+     * new template enums added in @3.4.
+     *
+     * The device must return a settings buffer that is configured to meet the
+     * requested use case, which must be one of the CAMERA3_TEMPLATE_*
+     * enums. All request control fields must be included.
+     *
+     * Performance requirements:
+     *
+     * This must be a non-blocking call. The HAL should return from this call
+     * in 1ms, and must return from this call in 5ms.
+     *
+     * Return values:
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On a successful construction of default settings.
+     *     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
+     *         instance must be acquired if the device is reconnected. All
+     *         subsequent calls on this interface must return
+     *         CAMERA_DISCONNECTED.
+     * @return requestTemplate The default capture request settings for the requested
+     *     use case, or an empty metadata structure if status is not OK.
+     *
+     */
+    constructDefaultRequestSettings_3_4(RequestTemplate type) generates
+            (Status status, @3.2::CameraMetadata requestTemplate);
+
+    /**
+     * configureStreams_3_4:
+     *
+     * Identical to @3.3::ICameraDeviceSession.configureStreams, except that:
+     *
+     * - The requested configuration includes session parameters.
+     *
+     * @return Status Status code for the operation, one of:
+     *     OK:
+     *          On successful stream configuration.
+     *     INTERNAL_ERROR:
+     *         If there has been a fatal error and the device is no longer
+     *         operational. Only close() can be called successfully by the
+     *         framework after this error is returned.
+     *     ILLEGAL_ARGUMENT:
+     *         If the requested stream configuration is invalid. Some examples
+     *         of invalid stream configurations include:
+     *           - Including more than 1 INPUT stream
+     *           - Not including any OUTPUT streams
+     *           - Including streams with unsupported formats, or an unsupported
+     *             size for that format.
+     *           - Including too many output streams of a certain format.
+     *           - Unsupported rotation configuration
+     *           - Stream sizes/formats don't satisfy the
+     *             camera3_stream_configuration_t->operation_mode requirements
+     *             for non-NORMAL mode, or the requested operation_mode is not
+     *             supported by the HAL.
+     *           - Unsupported usage flag
+     *         The camera service cannot filter out all possible illegal stream
+     *         configurations, since some devices may support more simultaneous
+     *         streams or larger stream resolutions than the minimum required
+     *         for a given camera device hardware level. The HAL must return an
+     *         ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+     *         ready to accept a future valid stream configuration in a later
+     *         configureStreams call.
+     * @return halConfiguration The stream parameters desired by the HAL for
+     *     each stream, including maximum buffers, the usage flags, and the
+     *     override format.
+     */
+    configureStreams_3_4(@3.4::StreamConfiguration requestedConfiguration)
+            generates (Status status,
+                       @3.4::HalStreamConfiguration halConfiguration);
+
+    /**
+     * processCaptureRequest_3_4:
+     *
+     * Identical to @3.2::ICameraDeviceSession.processCaptureRequest, except that:
+     *
+     * - The capture request can include individual settings for physical camera devices
+     *   backing a logical multi-camera.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On a successful start to processing the capture request
+     *     ILLEGAL_ARGUMENT:
+     *         If the input is malformed (the settings are empty when not
+     *         allowed, the physical camera settings are invalid, there are 0
+     *         output buffers, etc) and capture processing
+     *         cannot start. Failures during request processing must be
+     *         handled by calling ICameraDeviceCallback::notify(). In case of
+     *         this error, the framework retains responsibility for the
+     *         stream buffers' fences and the buffer handles; the HAL must not
+     *         close the fences or return these buffers with
+     *         ICameraDeviceCallback::processCaptureResult().
+     *     INTERNAL_ERROR:
+     *         If the camera device has encountered a serious error. After this
+     *         error is returned, only the close() method can be successfully
+     *         called by the framework.
+     * @return numRequestProcessed Number of requests successfully processed by
+     *     camera HAL. When status is OK, this must be equal to the size of
+     *     requests. When the call fails, this number is the number of requests
+     *     that HAL processed successfully before HAL runs into an error.
+     *
+     */
+    processCaptureRequest_3_4(vec<CaptureRequest> requests, vec<BufferCache> cachesToRemove)
+            generates (Status status, uint32_t numRequestProcessed);
+};
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
new file mode 100644
index 0000000..272bf42
--- /dev/null
+++ b/camera/device/3.4/default/Android.bp
@@ -0,0 +1,104 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+    name: "camera.device@3.4-impl_headers",
+    vendor: true,
+    export_include_dirs: ["include/device_v3_4_impl"]
+}
+
+cc_library_headers {
+    name: "camera.device@3.4-external-impl_headers",
+    vendor: true,
+    export_include_dirs: ["include/ext_device_v3_4_impl"]
+}
+
+cc_library_shared {
+    name: "camera.device@3.4-impl",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    vendor: true,
+    srcs: [
+        "CameraDevice.cpp",
+        "CameraDeviceSession.cpp",
+        "convert.cpp"
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libutils",
+        "libcutils",
+        "camera.device@3.2-impl",
+        "camera.device@3.3-impl",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.graphics.mapper@2.0",
+        "liblog",
+        "libhardware",
+        "libcamera_metadata",
+        "libfmq",
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    local_include_dirs: ["include/device_v3_4_impl"],
+    export_shared_lib_headers: [
+        "libfmq",
+    ],
+}
+
+cc_library_shared {
+    name: "camera.device@3.4-external-impl",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    vendor: true,
+    srcs: [
+        "ExternalCameraDevice.cpp",
+        "ExternalCameraDeviceSession.cpp",
+        "ExternalCameraUtils.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libutils",
+        "libcutils",
+        "camera.device@3.2-impl",
+        "camera.device@3.3-impl",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.graphics.mapper@2.0",
+        "liblog",
+        "libhardware",
+        "libcamera_metadata",
+        "libfmq",
+        "libsync",
+        "libyuv",
+        "libjpeg",
+        "libexif",
+        "libtinyxml2"
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    local_include_dirs: ["include/ext_device_v3_4_impl"],
+    export_shared_lib_headers: [
+        "libfmq",
+    ],
+}
diff --git a/camera/device/3.4/default/CameraDevice.cpp b/camera/device/3.4/default/CameraDevice.cpp
new file mode 100644
index 0000000..d73833a
--- /dev/null
+++ b/camera/device/3.4/default/CameraDevice.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamDev@3.4-impl"
+#include <log/log.h>
+
+#include <utils/Vector.h>
+#include <utils/Trace.h>
+#include "CameraDevice_3_4.h"
+#include <include/convert.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+using ::android::hardware::camera::common::V1_0::Status;
+using namespace ::android::hardware::camera::device;
+
+CameraDevice::CameraDevice(
+    sp<CameraModule> module, const std::string& cameraId,
+    const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) :
+        V3_2::implementation::CameraDevice(module, cameraId, cameraDeviceNames) {
+}
+
+CameraDevice::~CameraDevice() {
+}
+
+sp<V3_2::implementation::CameraDeviceSession> CameraDevice::createSession(camera3_device_t* device,
+        const camera_metadata_t* deviceInfo,
+        const sp<V3_2::ICameraDeviceCallback>& callback) {
+    sp<CameraDeviceSession> session = new CameraDeviceSession(device, deviceInfo, callback);
+    IF_ALOGV() {
+        session->getInterface()->interfaceChain([](
+            ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+                ALOGV("Session interface chain:");
+                for (auto iface : interfaceChain) {
+                    ALOGV("  %s", iface.c_str());
+                }
+            });
+    }
+    return session;
+}
+
+// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice.
+
+} // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.4/default/CameraDeviceSession.cpp b/camera/device/3.4/default/CameraDeviceSession.cpp
new file mode 100644
index 0000000..f6c6b2b
--- /dev/null
+++ b/camera/device/3.4/default/CameraDeviceSession.cpp
@@ -0,0 +1,673 @@
+/*
+ * Copyright (C) 2017-2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamDevSession@3.4-impl"
+#include <android/log.h>
+
+#include <set>
+#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_4 {
+namespace implementation {
+
+CameraDeviceSession::CameraDeviceSession(
+    camera3_device_t* device,
+    const camera_metadata_t* deviceInfo,
+    const sp<V3_2::ICameraDeviceCallback>& callback) :
+        V3_3::implementation::CameraDeviceSession(device, deviceInfo, callback),
+        mResultBatcher_3_4(callback) {
+
+    mHasCallback_3_4 = false;
+
+    auto castResult = ICameraDeviceCallback::castFrom(callback);
+    if (castResult.isOk()) {
+        sp<ICameraDeviceCallback> callback3_4 = castResult;
+        if (callback3_4 != nullptr) {
+            process_capture_result = sProcessCaptureResult_3_4;
+            notify = sNotify_3_4;
+            mHasCallback_3_4 = true;
+            if (!mInitFail) {
+                mResultBatcher_3_4.setResultMetadataQueue(mResultMetadataQueue);
+            }
+        }
+    }
+}
+
+CameraDeviceSession::~CameraDeviceSession() {
+}
+
+Return<void> CameraDeviceSession::constructDefaultRequestSettings_3_4(
+        RequestTemplate type, ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb)  {
+    V3_2::CameraMetadata outMetadata;
+    Status status = constructDefaultRequestSettingsRaw( (int) type, &outMetadata);
+    _hidl_cb(status, outMetadata);
+    return Void();
+}
+
+Return<void> CameraDeviceSession::configureStreams_3_4(
+        const StreamConfiguration& requestedConfiguration,
+        ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb)  {
+    Status status = initStatus();
+    HalStreamConfiguration outStreams;
+
+    // If callback is 3.2, make sure no physical stream is configured
+    if (!mHasCallback_3_4) {
+        for (size_t i = 0; i < requestedConfiguration.streams.size(); i++) {
+            if (requestedConfiguration.streams[i].physicalCameraId.size() > 0) {
+                ALOGE("%s: trying to configureStreams with physical camera id with V3.2 callback",
+                        __FUNCTION__);
+                _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+                return Void();
+            }
+        }
+    }
+
+    // hold the inflight lock for entire configureStreams scope since there must not be any
+    // inflight request/results during stream configuration.
+    Mutex::Autolock _l(mInflightLock);
+    if (!mInflightBuffers.empty()) {
+        ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!",
+                __FUNCTION__, mInflightBuffers.size());
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
+    }
+
+    if (!mInflightAETriggerOverrides.empty()) {
+        ALOGE("%s: trying to configureStreams while there are still %zu inflight"
+                " trigger overrides!", __FUNCTION__,
+                mInflightAETriggerOverrides.size());
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
+    }
+
+    if (!mInflightRawBoostPresent.empty()) {
+        ALOGE("%s: trying to configureStreams while there are still %zu inflight"
+                " boost overrides!", __FUNCTION__,
+                mInflightRawBoostPresent.size());
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
+    }
+
+    if (status != Status::OK) {
+        _hidl_cb(status, outStreams);
+        return Void();
+    }
+
+    const camera_metadata_t *paramBuffer = nullptr;
+    if (0 < requestedConfiguration.sessionParams.size()) {
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams;
+        V3_2::implementation::convertFromHidl(requestedConfiguration.sessionParams, &paramBuffer);
+    }
+
+    camera3_stream_configuration_t stream_list{};
+    hidl_vec<camera3_stream_t*> streams;
+    stream_list.session_parameters = paramBuffer;
+    if (!preProcessConfigurationLocked_3_4(requestedConfiguration, &stream_list, &streams)) {
+        _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+        return Void();
+    }
+
+    ATRACE_BEGIN("camera3->configure_streams");
+    status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list);
+    ATRACE_END();
+
+    // In case Hal returns error most likely it was not able to release
+    // the corresponding resources of the deleted streams.
+    if (ret == OK) {
+        postProcessConfigurationLocked_3_4(requestedConfiguration);
+    }
+
+    if (ret == -EINVAL) {
+        status = Status::ILLEGAL_ARGUMENT;
+    } else if (ret != OK) {
+        status = Status::INTERNAL_ERROR;
+    } else {
+        V3_4::implementation::convertToHidl(stream_list, &outStreams);
+        mFirstRequest = true;
+    }
+
+    _hidl_cb(status, outStreams);
+    return Void();
+}
+
+bool CameraDeviceSession::preProcessConfigurationLocked_3_4(
+        const StreamConfiguration& requestedConfiguration,
+        camera3_stream_configuration_t *stream_list /*out*/,
+        hidl_vec<camera3_stream_t*> *streams /*out*/) {
+
+    if ((stream_list == nullptr) || (streams == nullptr)) {
+        return false;
+    }
+
+    stream_list->operation_mode = (uint32_t) requestedConfiguration.operationMode;
+    stream_list->num_streams = requestedConfiguration.streams.size();
+    streams->resize(stream_list->num_streams);
+    stream_list->streams = streams->data();
+
+    for (uint32_t i = 0; i < stream_list->num_streams; i++) {
+        int id = requestedConfiguration.streams[i].v3_2.id;
+
+        if (mStreamMap.count(id) == 0) {
+            Camera3Stream stream;
+            convertFromHidl(requestedConfiguration.streams[i], &stream);
+            mStreamMap[id] = stream;
+            mPhysicalCameraIdMap[id] = requestedConfiguration.streams[i].physicalCameraId;
+            mStreamMap[id].data_space = mapToLegacyDataspace(
+                    mStreamMap[id].data_space);
+            mStreamMap[id].physical_camera_id = mPhysicalCameraIdMap[id].c_str();
+            mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
+        } else {
+            // width/height/format must not change, but usage/rotation might need to change
+            if (mStreamMap[id].stream_type !=
+                    (int) requestedConfiguration.streams[i].v3_2.streamType ||
+                    mStreamMap[id].width != requestedConfiguration.streams[i].v3_2.width ||
+                    mStreamMap[id].height != requestedConfiguration.streams[i].v3_2.height ||
+                    mStreamMap[id].format != (int) requestedConfiguration.streams[i].v3_2.format ||
+                    mStreamMap[id].data_space !=
+                            mapToLegacyDataspace( static_cast<android_dataspace_t> (
+                                    requestedConfiguration.streams[i].v3_2.dataSpace)) ||
+                    mPhysicalCameraIdMap[id] != requestedConfiguration.streams[i].physicalCameraId) {
+                ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
+                return false;
+            }
+            mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].v3_2.rotation;
+            mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].v3_2.usage;
+        }
+        (*streams)[i] = &mStreamMap[id];
+    }
+
+    return true;
+}
+
+void CameraDeviceSession::postProcessConfigurationLocked_3_4(
+        const StreamConfiguration& requestedConfiguration) {
+    // delete unused streams, note we do this after adding new streams to ensure new stream
+    // will not have the same address as deleted stream, and HAL has a chance to reference
+    // the to be deleted stream in configure_streams call
+    for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+        int id = it->first;
+        bool found = false;
+        for (const auto& stream : requestedConfiguration.streams) {
+            if (id == stream.v3_2.id) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            // Unmap all buffers of deleted stream
+            // in case the configuration call succeeds and HAL
+            // is able to release the corresponding resources too.
+            cleanupBuffersLocked(id);
+            it = mStreamMap.erase(it);
+        } else {
+            ++it;
+        }
+    }
+
+    // Track video streams
+    mVideoStreamIds.clear();
+    for (const auto& stream : requestedConfiguration.streams) {
+        if (stream.v3_2.streamType == StreamType::OUTPUT &&
+            stream.v3_2.usage &
+                graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) {
+            mVideoStreamIds.push_back(stream.v3_2.id);
+        }
+    }
+    mResultBatcher_3_4.setBatchedStreams(mVideoStreamIds);
+}
+
+Return<void> CameraDeviceSession::processCaptureRequest_3_4(
+        const hidl_vec<V3_4::CaptureRequest>& requests,
+        const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+        ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb)  {
+    updateBufferCaches(cachesToRemove);
+
+    uint32_t numRequestProcessed = 0;
+    Status s = Status::OK;
+    for (size_t i = 0; i < requests.size(); i++, numRequestProcessed++) {
+        s = processOneCaptureRequest_3_4(requests[i]);
+        if (s != Status::OK) {
+            break;
+        }
+    }
+
+    if (s == Status::OK && requests.size() > 1) {
+        mResultBatcher_3_4.registerBatch(requests[0].v3_2.frameNumber, requests.size());
+    }
+
+    _hidl_cb(s, numRequestProcessed);
+    return Void();
+}
+
+Status CameraDeviceSession::processOneCaptureRequest_3_4(const V3_4::CaptureRequest& request)  {
+    Status status = initStatus();
+    if (status != Status::OK) {
+        ALOGE("%s: camera init failed or disconnected", __FUNCTION__);
+        return status;
+    }
+    // If callback is 3.2, make sure there are no physical settings.
+    if (!mHasCallback_3_4) {
+        if (request.physicalCameraSettings.size() > 0) {
+            ALOGE("%s: trying to call processCaptureRequest_3_4 with physical camera id "
+                    "and V3.2 callback", __FUNCTION__);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+
+    camera3_capture_request_t halRequest;
+    halRequest.frame_number = request.v3_2.frameNumber;
+
+    bool converted = true;
+    V3_2::CameraMetadata settingsFmq;  // settings from FMQ
+    if (request.v3_2.fmqSettingsSize > 0) {
+        // non-blocking read; client must write metadata before calling
+        // processOneCaptureRequest
+        settingsFmq.resize(request.v3_2.fmqSettingsSize);
+        bool read = mRequestMetadataQueue->read(settingsFmq.data(), request.v3_2.fmqSettingsSize);
+        if (read) {
+            converted = V3_2::implementation::convertFromHidl(settingsFmq, &halRequest.settings);
+        } else {
+            ALOGE("%s: capture request settings metadata couldn't be read from fmq!", __FUNCTION__);
+            converted = false;
+        }
+    } else {
+        converted = V3_2::implementation::convertFromHidl(request.v3_2.settings,
+                &halRequest.settings);
+    }
+
+    if (!converted) {
+        ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (mFirstRequest && halRequest.settings == nullptr) {
+        ALOGE("%s: capture request settings must not be null for first request!",
+                __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    hidl_vec<buffer_handle_t*> allBufPtrs;
+    hidl_vec<int> allFences;
+    bool hasInputBuf = (request.v3_2.inputBuffer.streamId != -1 &&
+            request.v3_2.inputBuffer.bufferId != 0);
+    size_t numOutputBufs = request.v3_2.outputBuffers.size();
+    size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
+
+    if (numOutputBufs == 0) {
+        ALOGE("%s: capture request must have at least one output buffer!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    status = importRequest(request.v3_2, allBufPtrs, allFences);
+    if (status != Status::OK) {
+        return status;
+    }
+
+    hidl_vec<camera3_stream_buffer_t> outHalBufs;
+    outHalBufs.resize(numOutputBufs);
+    bool aeCancelTriggerNeeded = false;
+    ::android::hardware::camera::common::V1_0::helper::CameraMetadata settingsOverride;
+    {
+        Mutex::Autolock _l(mInflightLock);
+        if (hasInputBuf) {
+            auto streamId = request.v3_2.inputBuffer.streamId;
+            auto key = std::make_pair(request.v3_2.inputBuffer.streamId, request.v3_2.frameNumber);
+            auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
+            convertFromHidl(
+                    allBufPtrs[numOutputBufs], request.v3_2.inputBuffer.status,
+                    &mStreamMap[request.v3_2.inputBuffer.streamId], allFences[numOutputBufs],
+                    &bufCache);
+            bufCache.stream->physical_camera_id = mPhysicalCameraIdMap[streamId].c_str();
+            halRequest.input_buffer = &bufCache;
+        } else {
+            halRequest.input_buffer = nullptr;
+        }
+
+        halRequest.num_output_buffers = numOutputBufs;
+        for (size_t i = 0; i < numOutputBufs; i++) {
+            auto streamId = request.v3_2.outputBuffers[i].streamId;
+            auto key = std::make_pair(streamId, request.v3_2.frameNumber);
+            auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
+            convertFromHidl(
+                    allBufPtrs[i], request.v3_2.outputBuffers[i].status,
+                    &mStreamMap[streamId], allFences[i],
+                    &bufCache);
+            bufCache.stream->physical_camera_id = mPhysicalCameraIdMap[streamId].c_str();
+            outHalBufs[i] = bufCache;
+        }
+        halRequest.output_buffers = outHalBufs.data();
+
+        AETriggerCancelOverride triggerOverride;
+        aeCancelTriggerNeeded = handleAePrecaptureCancelRequestLocked(
+                halRequest, &settingsOverride /*out*/, &triggerOverride/*out*/);
+        if (aeCancelTriggerNeeded) {
+            mInflightAETriggerOverrides[halRequest.frame_number] =
+                    triggerOverride;
+            halRequest.settings = settingsOverride.getAndLock();
+        }
+    }
+
+    std::vector<const char *> physicalCameraIds;
+    std::vector<const camera_metadata_t *> physicalCameraSettings;
+    std::vector<V3_2::CameraMetadata> physicalFmq;
+    size_t settingsCount = request.physicalCameraSettings.size();
+    if (settingsCount > 0) {
+        physicalCameraIds.reserve(settingsCount);
+        physicalCameraSettings.reserve(settingsCount);
+        physicalFmq.reserve(settingsCount);
+
+        for (size_t i = 0; i < settingsCount; i++) {
+            uint64_t settingsSize = request.physicalCameraSettings[i].fmqSettingsSize;
+            const camera_metadata_t *settings;
+            if (settingsSize > 0) {
+                physicalFmq.push_back(V3_2::CameraMetadata(settingsSize));
+                bool read = mRequestMetadataQueue->read(physicalFmq[i].data(), settingsSize);
+                if (read) {
+                    converted = V3_2::implementation::convertFromHidl(physicalFmq[i], &settings);
+                    physicalCameraSettings.push_back(settings);
+                } else {
+                    ALOGE("%s: physical camera settings metadata couldn't be read from fmq!",
+                            __FUNCTION__);
+                    converted = false;
+                }
+            } else {
+                converted = V3_2::implementation::convertFromHidl(
+                        request.physicalCameraSettings[i].settings, &settings);
+                physicalCameraSettings.push_back(settings);
+            }
+
+            if (!converted) {
+                ALOGE("%s: physical camera settings metadata is corrupt!", __FUNCTION__);
+                return Status::ILLEGAL_ARGUMENT;
+            }
+            physicalCameraIds.push_back(request.physicalCameraSettings[i].physicalCameraId.c_str());
+        }
+    }
+    halRequest.num_physcam_settings = settingsCount;
+    halRequest.physcam_id = physicalCameraIds.data();
+    halRequest.physcam_settings = physicalCameraSettings.data();
+
+    ATRACE_ASYNC_BEGIN("frame capture", request.v3_2.frameNumber);
+    ATRACE_BEGIN("camera3->process_capture_request");
+    status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest);
+    ATRACE_END();
+    if (aeCancelTriggerNeeded) {
+        settingsOverride.unlock(halRequest.settings);
+    }
+    if (ret != OK) {
+        Mutex::Autolock _l(mInflightLock);
+        ALOGE("%s: HAL process_capture_request call failed!", __FUNCTION__);
+
+        cleanupInflightFences(allFences, numBufs);
+        if (hasInputBuf) {
+            auto key = std::make_pair(request.v3_2.inputBuffer.streamId, request.v3_2.frameNumber);
+            mInflightBuffers.erase(key);
+        }
+        for (size_t i = 0; i < numOutputBufs; i++) {
+            auto key = std::make_pair(request.v3_2.outputBuffers[i].streamId,
+                    request.v3_2.frameNumber);
+            mInflightBuffers.erase(key);
+        }
+        if (aeCancelTriggerNeeded) {
+            mInflightAETriggerOverrides.erase(request.v3_2.frameNumber);
+        }
+
+        if (ret == BAD_VALUE) {
+            return Status::ILLEGAL_ARGUMENT;
+        } else {
+            return Status::INTERNAL_ERROR;
+        }
+    }
+
+    mFirstRequest = false;
+    return Status::OK;
+}
+
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+void CameraDeviceSession::sProcessCaptureResult_3_4(
+        const camera3_callback_ops *cb,
+        const camera3_capture_result *hal_result) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+    CaptureResult result;
+    d->constructCaptureResult(result.v3_2, hal_result);
+    result.physicalCameraMetadata.resize(hal_result->num_physcam_metadata);
+    for (uint32_t i = 0; i < hal_result->num_physcam_metadata; i++) {
+        std::string physicalId = hal_result->physcam_ids[i];
+        V3_2::CameraMetadata physicalMetadata;
+        V3_2::implementation::convertToHidl(hal_result->physcam_metadata[i], &physicalMetadata);
+        PhysicalCameraMetadata physicalCameraMetadata = {
+                .fmqMetadataSize = 0,
+                .physicalCameraId = physicalId,
+                .metadata = physicalMetadata };
+        result.physicalCameraMetadata[i] = physicalCameraMetadata;
+    }
+    d->mResultBatcher_3_4.processCaptureResult_3_4(result);
+}
+
+void CameraDeviceSession::sNotify_3_4(
+        const camera3_callback_ops *cb,
+        const camera3_notify_msg *msg) {
+    CameraDeviceSession *d =
+            const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+    V3_2::NotifyMsg hidlMsg;
+    V3_2::implementation::convertToHidl(msg, &hidlMsg);
+
+    if (hidlMsg.type == (V3_2::MsgType) CAMERA3_MSG_ERROR &&
+            hidlMsg.msg.error.errorStreamId != -1) {
+        if (d->mStreamMap.count(hidlMsg.msg.error.errorStreamId) != 1) {
+            ALOGE("%s: unknown stream ID %d reports an error!",
+                    __FUNCTION__, hidlMsg.msg.error.errorStreamId);
+            return;
+        }
+    }
+
+    if (static_cast<camera3_msg_type_t>(hidlMsg.type) == CAMERA3_MSG_ERROR) {
+        switch (hidlMsg.msg.error.errorCode) {
+            case V3_2::ErrorCode::ERROR_DEVICE:
+            case V3_2::ErrorCode::ERROR_REQUEST:
+            case V3_2::ErrorCode::ERROR_RESULT: {
+                Mutex::Autolock _l(d->mInflightLock);
+                auto entry = d->mInflightAETriggerOverrides.find(
+                        hidlMsg.msg.error.frameNumber);
+                if (d->mInflightAETriggerOverrides.end() != entry) {
+                    d->mInflightAETriggerOverrides.erase(
+                            hidlMsg.msg.error.frameNumber);
+                }
+
+                auto boostEntry = d->mInflightRawBoostPresent.find(
+                        hidlMsg.msg.error.frameNumber);
+                if (d->mInflightRawBoostPresent.end() != boostEntry) {
+                    d->mInflightRawBoostPresent.erase(
+                            hidlMsg.msg.error.frameNumber);
+                }
+
+            }
+                break;
+            case V3_2::ErrorCode::ERROR_BUFFER:
+            default:
+                break;
+        }
+
+    }
+
+    d->mResultBatcher_3_4.notify(hidlMsg);
+}
+
+CameraDeviceSession::ResultBatcher_3_4::ResultBatcher_3_4(
+        const sp<V3_2::ICameraDeviceCallback>& callback) :
+        V3_3::implementation::CameraDeviceSession::ResultBatcher(callback) {
+    auto castResult = ICameraDeviceCallback::castFrom(callback);
+    if (castResult.isOk()) {
+        mCallback_3_4 = castResult;
+    }
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::processCaptureResult_3_4(CaptureResult& result) {
+    auto pair = getBatch(result.v3_2.frameNumber);
+    int batchIdx = pair.first;
+    if (batchIdx == NOT_BATCHED) {
+        processOneCaptureResult_3_4(result);
+        return;
+    }
+    std::shared_ptr<InflightBatch> batch = pair.second;
+    {
+        Mutex::Autolock _l(batch->mLock);
+        // Check if the batch is removed (mostly by notify error) before lock was acquired
+        if (batch->mRemoved) {
+            // Fall back to non-batch path
+            processOneCaptureResult_3_4(result);
+            return;
+        }
+
+        // queue metadata
+        if (result.v3_2.result.size() != 0) {
+            // Save a copy of metadata
+            batch->mResultMds[result.v3_2.partialResult].mMds.push_back(
+                    std::make_pair(result.v3_2.frameNumber, result.v3_2.result));
+        }
+
+        // queue buffer
+        std::vector<int> filledStreams;
+        std::vector<V3_2::StreamBuffer> nonBatchedBuffers;
+        for (auto& buffer : result.v3_2.outputBuffers) {
+            auto it = batch->mBatchBufs.find(buffer.streamId);
+            if (it != batch->mBatchBufs.end()) {
+                InflightBatch::BufferBatch& bb = it->second;
+                pushStreamBuffer(std::move(buffer), bb.mBuffers);
+                filledStreams.push_back(buffer.streamId);
+            } else {
+                pushStreamBuffer(std::move(buffer), nonBatchedBuffers);
+            }
+        }
+
+        // send non-batched buffers up
+        if (nonBatchedBuffers.size() > 0 || result.v3_2.inputBuffer.streamId != -1) {
+            CaptureResult nonBatchedResult;
+            nonBatchedResult.v3_2.frameNumber = result.v3_2.frameNumber;
+            nonBatchedResult.v3_2.fmqResultSize = 0;
+            nonBatchedResult.v3_2.outputBuffers.resize(nonBatchedBuffers.size());
+            for (size_t i = 0; i < nonBatchedBuffers.size(); i++) {
+                moveStreamBuffer(
+                        std::move(nonBatchedBuffers[i]), nonBatchedResult.v3_2.outputBuffers[i]);
+            }
+            moveStreamBuffer(std::move(result.v3_2.inputBuffer), nonBatchedResult.v3_2.inputBuffer);
+            nonBatchedResult.v3_2.partialResult = 0; // 0 for buffer only results
+            processOneCaptureResult_3_4(nonBatchedResult);
+        }
+
+        if (result.v3_2.frameNumber == batch->mLastFrame) {
+            // Send data up
+            if (result.v3_2.partialResult > 0) {
+                sendBatchMetadataLocked(batch, result.v3_2.partialResult);
+            }
+            // send buffer up
+            if (filledStreams.size() > 0) {
+                sendBatchBuffersLocked(batch, filledStreams);
+            }
+        }
+    } // end of batch lock scope
+
+    // see if the batch is complete
+    if (result.v3_2.frameNumber == batch->mLastFrame) {
+        checkAndRemoveFirstBatch();
+    }
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::processOneCaptureResult_3_4(CaptureResult& result) {
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    results[0] = std::move(result);
+    invokeProcessCaptureResultCallback_3_4(results, /* tryWriteFmq */true);
+    freeReleaseFences_3_4(results);
+    return;
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::invokeProcessCaptureResultCallback_3_4(
+        hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(1000000000 /* 1s */) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+                    __FUNCTION__);
+            return;
+        }
+    }
+    if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+        for (CaptureResult &result : results) {
+            if (result.v3_2.result.size() > 0) {
+                if (mResultMetadataQueue->write(result.v3_2.result.data(),
+                        result.v3_2.result.size())) {
+                    result.v3_2.fmqResultSize = result.v3_2.result.size();
+                    result.v3_2.result.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    result.v3_2.fmqResultSize = 0;
+                }
+            }
+
+            for (auto& onePhysMetadata : result.physicalCameraMetadata) {
+                if (mResultMetadataQueue->write(onePhysMetadata.metadata.data(),
+                        onePhysMetadata.metadata.size())) {
+                    onePhysMetadata.fmqMetadataSize = onePhysMetadata.metadata.size();
+                    onePhysMetadata.metadata.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    onePhysMetadata.fmqMetadataSize = 0;
+                }
+            }
+        }
+    }
+    mCallback_3_4->processCaptureResult_3_4(results);
+    mProcessCaptureResultLock.unlock();
+}
+
+void CameraDeviceSession::ResultBatcher_3_4::freeReleaseFences_3_4(hidl_vec<CaptureResult>& results) {
+    for (auto& result : results) {
+        if (result.v3_2.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+            native_handle_t* handle = const_cast<native_handle_t*>(
+                    result.v3_2.inputBuffer.releaseFence.getNativeHandle());
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+        for (auto& buf : result.v3_2.outputBuffers) {
+            if (buf.releaseFence.getNativeHandle() != nullptr) {
+                native_handle_t* handle = const_cast<native_handle_t*>(
+                        buf.releaseFence.getNativeHandle());
+                native_handle_close(handle);
+                native_handle_delete(handle);
+            }
+        }
+    }
+    return;
+}
+
+} // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
new file mode 100644
index 0000000..569acfd
--- /dev/null
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -0,0 +1,872 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ExtCamDev@3.4"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include <algorithm>
+#include <array>
+#include <linux/videodev2.h>
+#include "android-base/macros.h"
+#include "CameraMetadata.h"
+#include "../../3.2/default/include/convert.h"
+#include "ExternalCameraDevice_3_4.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+namespace {
+// Only support MJPEG for now as it seems to be the one supports higher fps
+// Other formats to consider in the future:
+// * V4L2_PIX_FMT_YVU420 (== YV12)
+// * V4L2_PIX_FMT_YVYU (YVYU: can be converted to YV12 or other YUV420_888 formats)
+const std::array<uint32_t, /*size*/1> kSupportedFourCCs {{
+    V4L2_PIX_FMT_MJPEG
+}}; // double braces required in C++11
+
+} // anonymous namespace
+
+ExternalCameraDevice::ExternalCameraDevice(const std::string& cameraId) :
+        mCameraId(cameraId),
+        mCfg(ExternalCameraDeviceConfig::loadFromCfg()) {
+
+    status_t ret = initCameraCharacteristics();
+    if (ret != OK) {
+        ALOGE("%s: init camera characteristics failed: errorno %d", __FUNCTION__, ret);
+        mInitFailed = true;
+    }
+}
+
+ExternalCameraDevice::~ExternalCameraDevice() {}
+
+bool ExternalCameraDevice::isInitFailed() {
+    return mInitFailed;
+}
+
+Return<void> ExternalCameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) {
+    CameraResourceCost resCost;
+    resCost.resourceCost = 100;
+    _hidl_cb(Status::OK, resCost);
+    return Void();
+}
+
+Return<void> ExternalCameraDevice::getCameraCharacteristics(
+        getCameraCharacteristics_cb _hidl_cb) {
+    Mutex::Autolock _l(mLock);
+    V3_2::CameraMetadata hidlChars;
+
+    if (isInitFailed()) {
+        _hidl_cb(Status::INTERNAL_ERROR, hidlChars);
+        return Void();
+    }
+
+    const camera_metadata_t* rawMetadata = mCameraCharacteristics.getAndLock();
+    V3_2::implementation::convertToHidl(rawMetadata, &hidlChars);
+    _hidl_cb(Status::OK, hidlChars);
+    mCameraCharacteristics.unlock(rawMetadata);
+    return Void();
+}
+
+Return<Status> ExternalCameraDevice::setTorchMode(TorchMode) {
+    return Status::METHOD_NOT_SUPPORTED;
+}
+
+Return<void> ExternalCameraDevice::open(
+        const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) {
+    Status status = Status::OK;
+    sp<ExternalCameraDeviceSession> session = nullptr;
+
+    if (callback == nullptr) {
+        ALOGE("%s: cannot open camera %s. callback is null!",
+                __FUNCTION__, mCameraId.c_str());
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+        return Void();
+    }
+
+    if (isInitFailed()) {
+        ALOGE("%s: cannot open camera %s. camera init failed!",
+                __FUNCTION__, mCameraId.c_str());
+        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+        return Void();
+    }
+
+    mLock.lock();
+
+    ALOGV("%s: Initializing device for camera %s", __FUNCTION__, mCameraId.c_str());
+    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();
+    }
+
+    unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
+    if (fd.get() < 0) {
+        ALOGE("%s: v4l2 device open %s failed: %s",
+                __FUNCTION__, mCameraId.c_str(), strerror(errno));
+        mLock.unlock();
+        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+        return Void();
+    }
+
+    session = new ExternalCameraDeviceSession(
+            callback, mCfg, mSupportedFormats, mCroppingType,
+            mCameraCharacteristics, std::move(fd));
+    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->getInterface());
+    return Void();
+}
+
+Return<void> ExternalCameraDevice::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();
+    }
+    auto 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();
+}
+
+
+status_t ExternalCameraDevice::initCameraCharacteristics() {
+    if (mCameraCharacteristics.isEmpty()) {
+        // init camera characteristics
+        unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
+        if (fd.get() < 0) {
+            ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mCameraId.c_str());
+            return DEAD_OBJECT;
+        }
+
+        status_t ret;
+        ret = initDefaultCharsKeys(&mCameraCharacteristics);
+        if (ret != OK) {
+            ALOGE("%s: init default characteristics key failed: errorno %d", __FUNCTION__, ret);
+            mCameraCharacteristics.clear();
+            return ret;
+        }
+
+        ret = initCameraControlsCharsKeys(fd.get(), &mCameraCharacteristics);
+        if (ret != OK) {
+            ALOGE("%s: init camera control characteristics key failed: errorno %d", __FUNCTION__, ret);
+            mCameraCharacteristics.clear();
+            return ret;
+        }
+
+        ret = initOutputCharsKeys(fd.get(), &mCameraCharacteristics);
+        if (ret != OK) {
+            ALOGE("%s: init output characteristics key failed: errorno %d", __FUNCTION__, ret);
+            mCameraCharacteristics.clear();
+            return ret;
+        }
+    }
+    return OK;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define UPDATE(tag, data, size)                    \
+do {                                               \
+  if (metadata->update((tag), (data), (size))) {   \
+    ALOGE("Update " #tag " failed!");              \
+    return -EINVAL;                                \
+  }                                                \
+} while (0)
+
+status_t ExternalCameraDevice::initDefaultCharsKeys(
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    const uint8_t hardware_level = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL;
+    UPDATE(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &hardware_level, 1);
+
+    // android.colorCorrection
+    const uint8_t availableAberrationModes[] = {
+        ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF};
+    UPDATE(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
+           availableAberrationModes, ARRAY_SIZE(availableAberrationModes));
+
+    // android.control
+    const uint8_t antibandingMode =
+        ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
+    UPDATE(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+           &antibandingMode, 1);
+
+    const int32_t controlMaxRegions[] = {/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0};
+    UPDATE(ANDROID_CONTROL_MAX_REGIONS, controlMaxRegions,
+           ARRAY_SIZE(controlMaxRegions));
+
+    const uint8_t videoStabilizationMode =
+        ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+    UPDATE(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+           &videoStabilizationMode, 1);
+
+    const uint8_t awbAvailableMode = ANDROID_CONTROL_AWB_MODE_AUTO;
+    UPDATE(ANDROID_CONTROL_AWB_AVAILABLE_MODES, &awbAvailableMode, 1);
+
+    const uint8_t aeAvailableMode = ANDROID_CONTROL_AE_MODE_ON;
+    UPDATE(ANDROID_CONTROL_AE_AVAILABLE_MODES, &aeAvailableMode, 1);
+
+    const uint8_t availableFffect = ANDROID_CONTROL_EFFECT_MODE_OFF;
+    UPDATE(ANDROID_CONTROL_AVAILABLE_EFFECTS, &availableFffect, 1);
+
+    const uint8_t controlAvailableModes[] = {ANDROID_CONTROL_MODE_OFF,
+                                             ANDROID_CONTROL_MODE_AUTO};
+    UPDATE(ANDROID_CONTROL_AVAILABLE_MODES, controlAvailableModes,
+           ARRAY_SIZE(controlAvailableModes));
+
+    // android.edge
+    const uint8_t edgeMode = ANDROID_EDGE_MODE_OFF;
+    UPDATE(ANDROID_EDGE_AVAILABLE_EDGE_MODES, &edgeMode, 1);
+
+    // android.flash
+    const uint8_t flashInfo = ANDROID_FLASH_INFO_AVAILABLE_FALSE;
+    UPDATE(ANDROID_FLASH_INFO_AVAILABLE, &flashInfo, 1);
+
+    // android.hotPixel
+    const uint8_t hotPixelMode = ANDROID_HOT_PIXEL_MODE_OFF;
+    UPDATE(ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES, &hotPixelMode, 1);
+
+    // android.jpeg
+    // TODO: b/72261675 See if we can provide thumbnail size for all jpeg aspect ratios
+    const int32_t jpegAvailableThumbnailSizes[] = {0, 0, 240, 180};
+    UPDATE(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, jpegAvailableThumbnailSizes,
+           ARRAY_SIZE(jpegAvailableThumbnailSizes));
+
+    const int32_t jpegMaxSize = mCfg.maxJpegBufSize;
+    UPDATE(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
+
+    const uint8_t jpegQuality = 90;
+    UPDATE(ANDROID_JPEG_QUALITY, &jpegQuality, 1);
+    UPDATE(ANDROID_JPEG_THUMBNAIL_QUALITY, &jpegQuality, 1);
+
+    const int32_t jpegOrientation = 0;
+    UPDATE(ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1);
+
+    // android.lens
+    const uint8_t focusDistanceCalibration =
+            ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
+    UPDATE(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION, &focusDistanceCalibration, 1);
+
+    const uint8_t opticalStabilizationMode =
+        ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
+    UPDATE(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
+           &opticalStabilizationMode, 1);
+
+    const uint8_t facing = ANDROID_LENS_FACING_EXTERNAL;
+    UPDATE(ANDROID_LENS_FACING, &facing, 1);
+
+    // android.noiseReduction
+    const uint8_t noiseReductionMode = ANDROID_NOISE_REDUCTION_MODE_OFF;
+    UPDATE(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
+           &noiseReductionMode, 1);
+    UPDATE(ANDROID_NOISE_REDUCTION_MODE, &noiseReductionMode, 1);
+
+    // android.request
+    const uint8_t availableCapabilities[] = {
+        ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE};
+    UPDATE(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, availableCapabilities,
+           ARRAY_SIZE(availableCapabilities));
+
+    const int32_t partialResultCount = 1;
+    UPDATE(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &partialResultCount, 1);
+
+    // This means pipeline latency of X frame intervals. The maximum number is 4.
+    const uint8_t requestPipelineMaxDepth = 4;
+    UPDATE(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &requestPipelineMaxDepth, 1);
+    UPDATE(ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
+
+    // Three numbers represent the maximum numbers of different types of output
+    // streams simultaneously. The types are raw sensor, processed (but not
+    // stalling), and processed (but stalling). For usb limited mode, raw sensor
+    // is not supported. Stalling stream is JPEG. Non-stalling streams are
+    // YUV_420_888 or YV12.
+    const int32_t requestMaxNumOutputStreams[] = {
+            /*RAW*/0,
+            /*Processed*/ExternalCameraDeviceSession::kMaxProcessedStream,
+            /*Stall*/ExternalCameraDeviceSession::kMaxStallStream};
+    UPDATE(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS, requestMaxNumOutputStreams,
+           ARRAY_SIZE(requestMaxNumOutputStreams));
+
+    // Limited mode doesn't support reprocessing.
+    const int32_t requestMaxNumInputStreams = 0;
+    UPDATE(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, &requestMaxNumInputStreams,
+           1);
+
+    // android.scaler
+    // TODO: b/72263447 V4L2_CID_ZOOM_*
+    const float scalerAvailableMaxDigitalZoom[] = {1};
+    UPDATE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+           scalerAvailableMaxDigitalZoom,
+           ARRAY_SIZE(scalerAvailableMaxDigitalZoom));
+
+    const uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;
+    UPDATE(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1);
+
+    const int32_t testPatternModes[] = {
+        ANDROID_SENSOR_TEST_PATTERN_MODE_OFF};
+    UPDATE(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, testPatternModes,
+           ARRAY_SIZE(testPatternModes));
+    UPDATE(ANDROID_SENSOR_TEST_PATTERN_MODE, &testPatternModes[0], 1);
+
+    const uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
+    UPDATE(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, &timestampSource, 1);
+
+    // Orientation probably isn't useful for external facing camera?
+    const int32_t orientation = 0;
+    UPDATE(ANDROID_SENSOR_ORIENTATION, &orientation, 1);
+
+    // android.shading
+    const uint8_t availabeMode = ANDROID_SHADING_MODE_OFF;
+    UPDATE(ANDROID_SHADING_AVAILABLE_MODES, &availabeMode, 1);
+
+    // android.statistics
+    const uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+    UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, &faceDetectMode,
+           1);
+
+    const int32_t maxFaceCount = 0;
+    UPDATE(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, &maxFaceCount, 1);
+
+    const uint8_t availableHotpixelMode =
+        ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
+    UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
+           &availableHotpixelMode, 1);
+
+    const uint8_t lensShadingMapMode =
+        ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+    UPDATE(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
+           &lensShadingMapMode, 1);
+
+    // android.sync
+    const int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;
+    UPDATE(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1);
+
+    /* Other sensor/RAW realted keys:
+     * android.sensor.info.colorFilterArrangement -> no need if we don't do RAW
+     * android.sensor.info.physicalSize           -> not available
+     * android.sensor.info.whiteLevel             -> not available/not needed
+     * android.sensor.info.lensShadingApplied     -> not needed
+     * android.sensor.info.preCorrectionActiveArraySize -> not available/not needed
+     * android.sensor.blackLevelPattern           -> not available/not needed
+     */
+
+    const int32_t availableRequestKeys[] = {
+        ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+        ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+        ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+        ANDROID_CONTROL_AE_LOCK,
+        ANDROID_CONTROL_AE_MODE,
+        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+        ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+        ANDROID_CONTROL_AF_MODE,
+        ANDROID_CONTROL_AF_TRIGGER,
+        ANDROID_CONTROL_AWB_LOCK,
+        ANDROID_CONTROL_AWB_MODE,
+        ANDROID_CONTROL_CAPTURE_INTENT,
+        ANDROID_CONTROL_EFFECT_MODE,
+        ANDROID_CONTROL_MODE,
+        ANDROID_CONTROL_SCENE_MODE,
+        ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+        ANDROID_FLASH_MODE,
+        ANDROID_JPEG_ORIENTATION,
+        ANDROID_JPEG_QUALITY,
+        ANDROID_JPEG_THUMBNAIL_QUALITY,
+        ANDROID_JPEG_THUMBNAIL_SIZE,
+        ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+        ANDROID_NOISE_REDUCTION_MODE,
+        ANDROID_SCALER_CROP_REGION,
+        ANDROID_SENSOR_TEST_PATTERN_MODE,
+        ANDROID_STATISTICS_FACE_DETECT_MODE,
+        ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE};
+    UPDATE(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, availableRequestKeys,
+           ARRAY_SIZE(availableRequestKeys));
+
+    const int32_t availableResultKeys[] = {
+        ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+        ANDROID_CONTROL_AE_ANTIBANDING_MODE,
+        ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
+        ANDROID_CONTROL_AE_LOCK,
+        ANDROID_CONTROL_AE_MODE,
+        ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
+        ANDROID_CONTROL_AE_STATE,
+        ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
+        ANDROID_CONTROL_AF_MODE,
+        ANDROID_CONTROL_AF_STATE,
+        ANDROID_CONTROL_AF_TRIGGER,
+        ANDROID_CONTROL_AWB_LOCK,
+        ANDROID_CONTROL_AWB_MODE,
+        ANDROID_CONTROL_AWB_STATE,
+        ANDROID_CONTROL_CAPTURE_INTENT,
+        ANDROID_CONTROL_EFFECT_MODE,
+        ANDROID_CONTROL_MODE,
+        ANDROID_CONTROL_SCENE_MODE,
+        ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
+        ANDROID_FLASH_MODE,
+        ANDROID_FLASH_STATE,
+        ANDROID_JPEG_ORIENTATION,
+        ANDROID_JPEG_QUALITY,
+        ANDROID_JPEG_THUMBNAIL_QUALITY,
+        ANDROID_JPEG_THUMBNAIL_SIZE,
+        ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
+        ANDROID_NOISE_REDUCTION_MODE,
+        ANDROID_REQUEST_PIPELINE_DEPTH,
+        ANDROID_SCALER_CROP_REGION,
+        ANDROID_SENSOR_TIMESTAMP,
+        ANDROID_STATISTICS_FACE_DETECT_MODE,
+        ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
+        ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
+        ANDROID_STATISTICS_SCENE_FLICKER};
+    UPDATE(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, availableResultKeys,
+           ARRAY_SIZE(availableResultKeys));
+
+    const int32_t availableCharacteristicsKeys[] = {
+        ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
+        ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
+        ANDROID_CONTROL_AE_AVAILABLE_MODES,
+        ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
+        ANDROID_CONTROL_AE_COMPENSATION_RANGE,
+        ANDROID_CONTROL_AE_COMPENSATION_STEP,
+        ANDROID_CONTROL_AE_LOCK_AVAILABLE,
+        ANDROID_CONTROL_AF_AVAILABLE_MODES,
+        ANDROID_CONTROL_AVAILABLE_EFFECTS,
+        ANDROID_CONTROL_AVAILABLE_MODES,
+        ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
+        ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
+        ANDROID_CONTROL_AWB_AVAILABLE_MODES,
+        ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
+        ANDROID_CONTROL_MAX_REGIONS,
+        ANDROID_FLASH_INFO_AVAILABLE,
+        ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
+        ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
+        ANDROID_LENS_FACING,
+        ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
+        ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
+        ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
+        ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+        ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
+        ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
+        ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
+        ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
+        ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+        ANDROID_SCALER_CROPPING_TYPE,
+        ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+        ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
+        ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
+        ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+        ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
+        ANDROID_SENSOR_ORIENTATION,
+        ANDROID_SHADING_AVAILABLE_MODES,
+        ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
+        ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
+        ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
+        ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
+        ANDROID_SYNC_MAX_LATENCY};
+    UPDATE(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
+           availableCharacteristicsKeys,
+           ARRAY_SIZE(availableCharacteristicsKeys));
+
+    return OK;
+}
+
+status_t ExternalCameraDevice::initCameraControlsCharsKeys(int,
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    /**
+     * android.sensor.info.sensitivityRange   -> V4L2_CID_ISO_SENSITIVITY
+     * android.sensor.info.exposureTimeRange  -> V4L2_CID_EXPOSURE_ABSOLUTE
+     * android.sensor.info.maxFrameDuration   -> TBD
+     * android.lens.info.minimumFocusDistance -> V4L2_CID_FOCUS_ABSOLUTE
+     * android.lens.info.hyperfocalDistance
+     * android.lens.info.availableFocalLengths -> not available?
+     */
+
+    // android.control
+    // No AE compensation support for now.
+    // TODO: V4L2_CID_EXPOSURE_BIAS
+    const int32_t controlAeCompensationRange[] = {0, 0};
+    UPDATE(ANDROID_CONTROL_AE_COMPENSATION_RANGE, controlAeCompensationRange,
+           ARRAY_SIZE(controlAeCompensationRange));
+    const camera_metadata_rational_t controlAeCompensationStep[] = {{0, 1}};
+    UPDATE(ANDROID_CONTROL_AE_COMPENSATION_STEP, controlAeCompensationStep,
+           ARRAY_SIZE(controlAeCompensationStep));
+
+
+    // TODO: Check V4L2_CID_AUTO_FOCUS_*.
+    const uint8_t afAvailableModes[] = {ANDROID_CONTROL_AF_MODE_AUTO,
+                                        ANDROID_CONTROL_AF_MODE_OFF};
+    UPDATE(ANDROID_CONTROL_AF_AVAILABLE_MODES, afAvailableModes,
+           ARRAY_SIZE(afAvailableModes));
+
+    // TODO: V4L2_CID_SCENE_MODE
+    const uint8_t availableSceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
+    UPDATE(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, &availableSceneMode, 1);
+
+    // TODO: V4L2_CID_3A_LOCK
+    const uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
+    UPDATE(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailable, 1);
+    const uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
+    UPDATE(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &awbLockAvailable, 1);
+
+    // TODO: V4L2_CID_ZOOM_*
+    const float scalerAvailableMaxDigitalZoom[] = {1};
+    UPDATE(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
+           scalerAvailableMaxDigitalZoom,
+           ARRAY_SIZE(scalerAvailableMaxDigitalZoom));
+
+    return OK;
+}
+
+status_t ExternalCameraDevice::initOutputCharsKeys(int fd,
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata* metadata) {
+    initSupportedFormatsLocked(fd);
+    if (mSupportedFormats.empty()) {
+        ALOGE("%s: Init supported format list failed", __FUNCTION__);
+        return UNKNOWN_ERROR;
+    }
+
+    std::vector<int32_t> streamConfigurations;
+    std::vector<int64_t> minFrameDurations;
+    std::vector<int64_t> stallDurations;
+    int64_t maxFrameDuration = 0;
+    int32_t maxFps = std::numeric_limits<int32_t>::min();
+    int32_t minFps = std::numeric_limits<int32_t>::max();
+    std::set<int32_t> framerates;
+
+    std::array<int, /*size*/3> halFormats{{
+        HAL_PIXEL_FORMAT_BLOB,
+        HAL_PIXEL_FORMAT_YCbCr_420_888,
+        HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}};
+
+    for (const auto& supportedFormat : mSupportedFormats) {
+        for (const auto& format : halFormats) {
+            streamConfigurations.push_back(format);
+            streamConfigurations.push_back(supportedFormat.width);
+            streamConfigurations.push_back(supportedFormat.height);
+            streamConfigurations.push_back(
+                    ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
+        }
+
+        int64_t min_frame_duration = std::numeric_limits<int64_t>::max();
+        for (const auto& frameRate : supportedFormat.frameRates) {
+            int64_t frame_duration = 1000000000LL / frameRate;
+            if (frame_duration < min_frame_duration) {
+                min_frame_duration = frame_duration;
+            }
+            if (frame_duration > maxFrameDuration) {
+                maxFrameDuration = frame_duration;
+            }
+            int32_t frameRateInt = static_cast<int32_t>(frameRate);
+            if (minFps > frameRateInt) {
+                minFps = frameRateInt;
+            }
+            if (maxFps < frameRateInt) {
+                maxFps = frameRateInt;
+            }
+            framerates.insert(frameRateInt);
+        }
+
+        for (const auto& format : halFormats) {
+            minFrameDurations.push_back(format);
+            minFrameDurations.push_back(supportedFormat.width);
+            minFrameDurations.push_back(supportedFormat.height);
+            minFrameDurations.push_back(min_frame_duration);
+        }
+
+        // The stall duration is 0 for non-jpeg formats. For JPEG format, stall
+        // duration can be 0 if JPEG is small. Here we choose 1 sec for JPEG.
+        // TODO: b/72261675. Maybe set this dynamically
+        for (const auto& format : halFormats) {
+            const int64_t NS_TO_SECOND = 1000000000;
+            int64_t stall_duration =
+                    (format == HAL_PIXEL_FORMAT_BLOB) ? NS_TO_SECOND : 0;
+            stallDurations.push_back(format);
+            stallDurations.push_back(supportedFormat.width);
+            stallDurations.push_back(supportedFormat.height);
+            stallDurations.push_back(stall_duration);
+        }
+    }
+
+    // The document in aeAvailableTargetFpsRanges section says the minFps should
+    // not be larger than 15.
+    // We cannot support fixed 30fps but Android requires (min, max) and
+    // (max, max) ranges.
+    // TODO: populate more, right now this does not support 30,30 if the device
+    //       has higher than 30 fps modes
+    std::vector<int32_t> fpsRanges;
+    // Variable range
+    fpsRanges.push_back(minFps);
+    fpsRanges.push_back(maxFps);
+    // Fixed ranges
+    for (const auto& framerate : framerates) {
+        fpsRanges.push_back(framerate);
+        fpsRanges.push_back(framerate);
+    }
+    UPDATE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, fpsRanges.data(),
+           fpsRanges.size());
+
+    UPDATE(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+           streamConfigurations.data(), streamConfigurations.size());
+
+    UPDATE(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
+           minFrameDurations.data(), minFrameDurations.size());
+
+    UPDATE(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, stallDurations.data(),
+           stallDurations.size());
+
+    UPDATE(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, &maxFrameDuration, 1);
+
+    SupportedV4L2Format maximumFormat {.width = 0, .height = 0};
+    for (const auto& supportedFormat : mSupportedFormats) {
+        if (supportedFormat.width >= maximumFormat.width &&
+            supportedFormat.height >= maximumFormat.height) {
+            maximumFormat = supportedFormat;
+        }
+    }
+    int32_t activeArraySize[] = {0, 0,
+                                 static_cast<int32_t>(maximumFormat.width),
+                                 static_cast<int32_t>(maximumFormat.height)};
+    UPDATE(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+           activeArraySize, ARRAY_SIZE(activeArraySize));
+    UPDATE(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArraySize,
+           ARRAY_SIZE(activeArraySize));
+
+    int32_t pixelArraySize[] = {static_cast<int32_t>(maximumFormat.width),
+                                static_cast<int32_t>(maximumFormat.height)};
+    UPDATE(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, pixelArraySize,
+           ARRAY_SIZE(pixelArraySize));
+    return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
+void ExternalCameraDevice::getFrameRateList(
+        int fd, float fpsUpperBound, SupportedV4L2Format* format) {
+    format->frameRates.clear();
+
+    v4l2_frmivalenum frameInterval {
+        .pixel_format = format->fourcc,
+        .width = format->width,
+        .height = format->height,
+        .index = 0
+    };
+
+    for (frameInterval.index = 0;
+            TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameInterval)) == 0;
+            ++frameInterval.index) {
+        if (frameInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
+            if (frameInterval.discrete.numerator != 0) {
+                float framerate = frameInterval.discrete.denominator /
+                        static_cast<float>(frameInterval.discrete.numerator);
+                if (framerate > fpsUpperBound) {
+                    continue;
+                }
+                ALOGI("index:%d, format:%c%c%c%c, w %d, h %d, framerate %f",
+                    frameInterval.index,
+                    frameInterval.pixel_format & 0xFF,
+                    (frameInterval.pixel_format >> 8) & 0xFF,
+                    (frameInterval.pixel_format >> 16) & 0xFF,
+                    (frameInterval.pixel_format >> 24) & 0xFF,
+                    frameInterval.width, frameInterval.height, framerate);
+                format->frameRates.push_back(framerate);
+            }
+        }
+    }
+
+    if (format->frameRates.empty()) {
+        ALOGE("%s: failed to get supported frame rates for format:%c%c%c%c w %d h %d",
+                __FUNCTION__,
+                frameInterval.pixel_format & 0xFF,
+                (frameInterval.pixel_format >> 8) & 0xFF,
+                (frameInterval.pixel_format >> 16) & 0xFF,
+                (frameInterval.pixel_format >> 24) & 0xFF,
+                frameInterval.width, frameInterval.height);
+    }
+}
+
+CroppingType ExternalCameraDevice::initCroppingType(
+        /*inout*/std::vector<SupportedV4L2Format>* pSortedFmts) {
+    std::vector<SupportedV4L2Format>& sortedFmts = *pSortedFmts;
+    const auto& maxSize = sortedFmts[sortedFmts.size() - 1];
+    float maxSizeAr = ASPECT_RATIO(maxSize);
+    float minAr = kMaxAspectRatio;
+    float maxAr = kMinAspectRatio;
+    for (const auto& fmt : sortedFmts) {
+        float ar = ASPECT_RATIO(fmt);
+        if (ar < minAr) {
+            minAr = ar;
+        }
+        if (ar > maxAr) {
+            maxAr = ar;
+        }
+    }
+
+    CroppingType ct = VERTICAL;
+    if (isAspectRatioClose(maxSizeAr, maxAr)) {
+        // Ex: 16:9 sensor, cropping horizontally to get to 4:3
+        ct = HORIZONTAL;
+    } else if (isAspectRatioClose(maxSizeAr, minAr)) {
+        // Ex: 4:3 sensor, cropping vertically to get to 16:9
+        ct = VERTICAL;
+    } else {
+        ALOGI("%s: camera maxSizeAr %f is not close to minAr %f or maxAr %f",
+                __FUNCTION__, maxSizeAr, minAr, maxAr);
+        if ((maxSizeAr - minAr) < (maxAr - maxSizeAr)) {
+            ct = VERTICAL;
+        } else {
+            ct = HORIZONTAL;
+        }
+
+        // Remove formats that has aspect ratio not croppable from largest size
+        std::vector<SupportedV4L2Format> out;
+        for (const auto& fmt : sortedFmts) {
+            float ar = ASPECT_RATIO(fmt);
+            if (isAspectRatioClose(ar, maxSizeAr)) {
+                out.push_back(fmt);
+            } else if (ct == HORIZONTAL && ar < maxSizeAr) {
+                out.push_back(fmt);
+            } else if (ct == VERTICAL && ar > maxSizeAr) {
+                out.push_back(fmt);
+            } else {
+                ALOGD("%s: size (%d,%d) is removed due to unable to crop %s from (%d,%d)",
+                    __FUNCTION__, fmt.width, fmt.height,
+                    ct == VERTICAL ? "vertically" : "horizontally",
+                    maxSize.width, maxSize.height);
+            }
+        }
+        sortedFmts = out;
+    }
+    ALOGI("%s: camera croppingType is %s", __FUNCTION__,
+            ct == VERTICAL ? "VERTICAL" : "HORIZONTAL");
+    return ct;
+}
+
+void ExternalCameraDevice::initSupportedFormatsLocked(int fd) {
+    struct v4l2_fmtdesc fmtdesc {
+        .index = 0,
+        .type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
+    int ret = 0;
+    while (ret == 0) {
+        ret = TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc));
+        ALOGD("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret,
+                fmtdesc.pixelformat & 0xFF,
+                (fmtdesc.pixelformat >> 8) & 0xFF,
+                (fmtdesc.pixelformat >> 16) & 0xFF,
+                (fmtdesc.pixelformat >> 24) & 0xFF);
+        if (ret == 0 && !(fmtdesc.flags & V4L2_FMT_FLAG_EMULATED)) {
+            auto it = std::find (
+                    kSupportedFourCCs.begin(), kSupportedFourCCs.end(), fmtdesc.pixelformat);
+            if (it != kSupportedFourCCs.end()) {
+                // Found supported format
+                v4l2_frmsizeenum frameSize {
+                        .index = 0,
+                        .pixel_format = fmtdesc.pixelformat};
+                for (; TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frameSize)) == 0;
+                        ++frameSize.index) {
+                    if (frameSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+                        ALOGV("index:%d, format:%c%c%c%c, w %d, h %d", frameSize.index,
+                            fmtdesc.pixelformat & 0xFF,
+                            (fmtdesc.pixelformat >> 8) & 0xFF,
+                            (fmtdesc.pixelformat >> 16) & 0xFF,
+                            (fmtdesc.pixelformat >> 24) & 0xFF,
+                            frameSize.discrete.width, frameSize.discrete.height);
+                        // Disregard h > w formats so all aspect ratio (h/w) <= 1.0
+                        // This will simplify the crop/scaling logic down the road
+                        if (frameSize.discrete.height > frameSize.discrete.width) {
+                            continue;
+                        }
+                        SupportedV4L2Format format {
+                            .width = frameSize.discrete.width,
+                            .height = frameSize.discrete.height,
+                            .fourcc = fmtdesc.pixelformat
+                        };
+
+                        float fpsUpperBound = -1.0;
+                        for (const auto& limit : mCfg.fpsLimits) {
+                            if (format.width <= limit.size.width &&
+                                    format.height <= limit.size.height) {
+                                fpsUpperBound = limit.fpsUpperBound;
+                                break;
+                            }
+                        }
+                        if (fpsUpperBound < 0.f) {
+                            continue;
+                        }
+
+                        getFrameRateList(fd, fpsUpperBound, &format);
+                        if (!format.frameRates.empty()) {
+                            mSupportedFormats.push_back(format);
+                        }
+                    }
+                }
+            }
+        }
+        fmtdesc.index++;
+    }
+
+    std::sort(mSupportedFormats.begin(), mSupportedFormats.end(),
+            [](const SupportedV4L2Format& a, const SupportedV4L2Format& b) -> bool {
+                if (a.width == b.width) {
+                    return a.height < b.height;
+                }
+                return a.width < b.width;
+            });
+
+    mCroppingType = initCroppingType(&mSupportedFormats);
+}
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
new file mode 100644
index 0000000..51bfe36
--- /dev/null
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -0,0 +1,2487 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "ExtCamDevSsn@3.4"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include <inttypes.h>
+#include "ExternalCameraDeviceSession.h"
+
+#include "android-base/macros.h"
+#include <utils/Timers.h>
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <jpeglib.h>
+
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+namespace {
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+const int kBadFramesAfterStreamOn = 1; // drop x frames after streamOn to get rid of some initial
+                                       // bad frames. TODO: develop a better bad frame detection
+                                       // method
+
+} // Anonymous namespace
+
+// Static instances
+const int ExternalCameraDeviceSession::kMaxProcessedStream;
+const int ExternalCameraDeviceSession::kMaxStallStream;
+HandleImporter ExternalCameraDeviceSession::sHandleImporter;
+
+ExternalCameraDeviceSession::ExternalCameraDeviceSession(
+        const sp<ICameraDeviceCallback>& callback,
+        const ExternalCameraDeviceConfig& cfg,
+        const std::vector<SupportedV4L2Format>& sortedFormats,
+        const CroppingType& croppingType,
+        const common::V1_0::helper::CameraMetadata& chars,
+        unique_fd v4l2Fd) :
+        mCallback(callback),
+        mCfg(cfg),
+        mCameraCharacteristics(chars),
+        mSupportedFormats(sortedFormats),
+        mCroppingType(croppingType),
+        mV4l2Fd(std::move(v4l2Fd)),
+        mOutputThread(new OutputThread(this, mCroppingType)),
+        mMaxThumbResolution(getMaxThumbResolution()),
+        mMaxJpegResolution(getMaxJpegResolution()) {
+    mInitFail = initialize();
+}
+
+bool ExternalCameraDeviceSession::initialize() {
+    if (mV4l2Fd.get() < 0) {
+        ALOGE("%s: invalid v4l2 device fd %d!", __FUNCTION__, mV4l2Fd.get());
+        return true;
+    }
+
+    status_t status = initDefaultRequests();
+    if (status != OK) {
+        ALOGE("%s: init default requests failed!", __FUNCTION__);
+        return true;
+    }
+
+    mRequestMetadataQueue = std::make_unique<RequestMetadataQueue>(
+            kMetadataMsgQueueSize, false /* non blocking */);
+    if (!mRequestMetadataQueue->isValid()) {
+        ALOGE("%s: invalid request fmq", __FUNCTION__);
+        return true;
+    }
+    mResultMetadataQueue = std::make_shared<RequestMetadataQueue>(
+            kMetadataMsgQueueSize, false /* non blocking */);
+    if (!mResultMetadataQueue->isValid()) {
+        ALOGE("%s: invalid result fmq", __FUNCTION__);
+        return true;
+    }
+
+    // TODO: check is PRIORITY_DISPLAY enough?
+    mOutputThread->run("ExtCamOut", PRIORITY_DISPLAY);
+    return false;
+}
+
+Status ExternalCameraDeviceSession::initStatus() const {
+    Mutex::Autolock _l(mLock);
+    Status status = Status::OK;
+    if (mInitFail || mClosed) {
+        ALOGI("%s: sesssion initFailed %d closed %d", __FUNCTION__, mInitFail, mClosed);
+        status = Status::INTERNAL_ERROR;
+    }
+    return status;
+}
+
+ExternalCameraDeviceSession::~ExternalCameraDeviceSession() {
+    if (!isClosed()) {
+        ALOGE("ExternalCameraDeviceSession deleted before close!");
+        close();
+    }
+}
+
+void ExternalCameraDeviceSession::dumpState(const native_handle_t*) {
+    // TODO: b/72261676 dump more runtime information
+}
+
+Return<void> ExternalCameraDeviceSession::constructDefaultRequestSettings(
+        V3_2::RequestTemplate type,
+        V3_2::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) {
+    V3_2::CameraMetadata outMetadata;
+    Status status = constructDefaultRequestSettingsRaw(
+            static_cast<RequestTemplate>(type), &outMetadata);
+    _hidl_cb(status, outMetadata);
+    return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::constructDefaultRequestSettings_3_4(
+        RequestTemplate type,
+        ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb)  {
+    V3_2::CameraMetadata outMetadata;
+    Status status = constructDefaultRequestSettingsRaw(type, &outMetadata);
+    _hidl_cb(status, outMetadata);
+    return Void();
+}
+
+Status ExternalCameraDeviceSession::constructDefaultRequestSettingsRaw(RequestTemplate type,
+        V3_2::CameraMetadata *outMetadata) {
+    CameraMetadata emptyMd;
+    Status status = initStatus();
+    if (status != Status::OK) {
+        return status;
+    }
+
+    switch (type) {
+        case RequestTemplate::PREVIEW:
+        case RequestTemplate::STILL_CAPTURE:
+        case RequestTemplate::VIDEO_RECORD:
+        case RequestTemplate::VIDEO_SNAPSHOT: {
+            *outMetadata = mDefaultRequests[type];
+            break;
+        }
+        case RequestTemplate::MANUAL:
+        case RequestTemplate::ZERO_SHUTTER_LAG:
+        case RequestTemplate::MOTION_TRACKING_PREVIEW:
+        case RequestTemplate::MOTION_TRACKING_BEST:
+            // Don't support MANUAL, ZSL, MOTION_TRACKING_* templates
+            status = Status::ILLEGAL_ARGUMENT;
+            break;
+        default:
+            ALOGE("%s: unknown request template type %d", __FUNCTION__, static_cast<int>(type));
+            status = Status::ILLEGAL_ARGUMENT;
+            break;
+    }
+    return status;
+}
+
+Return<void> ExternalCameraDeviceSession::configureStreams(
+        const V3_2::StreamConfiguration& streams,
+        ICameraDeviceSession::configureStreams_cb _hidl_cb) {
+    V3_2::HalStreamConfiguration outStreams;
+    V3_3::HalStreamConfiguration outStreams_v33;
+    Mutex::Autolock _il(mInterfaceLock);
+
+    Status status = configureStreams(streams, &outStreams_v33);
+    size_t size = outStreams_v33.streams.size();
+    outStreams.streams.resize(size);
+    for (size_t i = 0; i < size; i++) {
+        outStreams.streams[i] = outStreams_v33.streams[i].v3_2;
+    }
+    _hidl_cb(status, outStreams);
+    return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::configureStreams_3_3(
+        const V3_2::StreamConfiguration& streams,
+        ICameraDeviceSession::configureStreams_3_3_cb _hidl_cb) {
+    V3_3::HalStreamConfiguration outStreams;
+    Mutex::Autolock _il(mInterfaceLock);
+
+    Status status = configureStreams(streams, &outStreams);
+    _hidl_cb(status, outStreams);
+    return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::configureStreams_3_4(
+        const V3_4::StreamConfiguration& requestedConfiguration,
+        ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb)  {
+    V3_2::StreamConfiguration config_v32;
+    V3_3::HalStreamConfiguration outStreams_v33;
+    Mutex::Autolock _il(mInterfaceLock);
+
+    config_v32.operationMode = requestedConfiguration.operationMode;
+    config_v32.streams.resize(requestedConfiguration.streams.size());
+    for (size_t i = 0; i < config_v32.streams.size(); i++) {
+        config_v32.streams[i] = requestedConfiguration.streams[i].v3_2;
+    }
+
+    // Ignore requestedConfiguration.sessionParams. External camera does not support it
+    Status status = configureStreams(config_v32, &outStreams_v33);
+
+    V3_4::HalStreamConfiguration outStreams;
+    outStreams.streams.resize(outStreams_v33.streams.size());
+    for (size_t i = 0; i < outStreams.streams.size(); i++) {
+        outStreams.streams[i].v3_3 = outStreams_v33.streams[i];
+    }
+    _hidl_cb(status, outStreams);
+    return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::getCaptureRequestMetadataQueue(
+    ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    _hidl_cb(*mRequestMetadataQueue->getDesc());
+    return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::getCaptureResultMetadataQueue(
+    ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    _hidl_cb(*mResultMetadataQueue->getDesc());
+    return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::processCaptureRequest(
+        const hidl_vec<CaptureRequest>& requests,
+        const hidl_vec<BufferCache>& cachesToRemove,
+        ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    updateBufferCaches(cachesToRemove);
+
+    uint32_t numRequestProcessed = 0;
+    Status s = Status::OK;
+    for (size_t i = 0; i < requests.size(); i++, numRequestProcessed++) {
+        s = processOneCaptureRequest(requests[i]);
+        if (s != Status::OK) {
+            break;
+        }
+    }
+
+    _hidl_cb(s, numRequestProcessed);
+    return Void();
+}
+
+Return<void> ExternalCameraDeviceSession::processCaptureRequest_3_4(
+        const hidl_vec<V3_4::CaptureRequest>& requests,
+        const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+        ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) {
+    Mutex::Autolock _il(mInterfaceLock);
+    updateBufferCaches(cachesToRemove);
+
+    uint32_t numRequestProcessed = 0;
+    Status s = Status::OK;
+    for (size_t i = 0; i < requests.size(); i++, numRequestProcessed++) {
+        s = processOneCaptureRequest(requests[i].v3_2);
+        if (s != Status::OK) {
+            break;
+        }
+    }
+
+    _hidl_cb(s, numRequestProcessed);
+    return Void();
+}
+
+Return<Status> ExternalCameraDeviceSession::flush() {
+    return Status::OK;
+}
+
+Return<void> ExternalCameraDeviceSession::close() {
+    Mutex::Autolock _il(mInterfaceLock);
+    Mutex::Autolock _l(mLock);
+    if (!mClosed) {
+        // TODO: b/72261676 Cleanup inflight buffers/V4L2 buffer queue
+        ALOGV("%s: closing V4L2 camera FD %d", __FUNCTION__, mV4l2Fd.get());
+        mV4l2Fd.reset();
+        mOutputThread->requestExit(); // TODO: join?
+
+        // free all imported buffers
+        for(auto& pair : mCirculatingBuffers) {
+            CirculatingBuffers& buffers = pair.second;
+            for (auto& p2 : buffers) {
+                sHandleImporter.freeBuffer(p2.second);
+            }
+        }
+
+        mClosed = true;
+    }
+    return Void();
+}
+
+Status ExternalCameraDeviceSession::importRequest(
+        const CaptureRequest& request,
+        hidl_vec<buffer_handle_t*>& allBufPtrs,
+        hidl_vec<int>& allFences) {
+    size_t numOutputBufs = request.outputBuffers.size();
+    size_t numBufs = numOutputBufs;
+    // Validate all I/O buffers
+    hidl_vec<buffer_handle_t> allBufs;
+    hidl_vec<uint64_t> allBufIds;
+    allBufs.resize(numBufs);
+    allBufIds.resize(numBufs);
+    allBufPtrs.resize(numBufs);
+    allFences.resize(numBufs);
+    std::vector<int32_t> streamIds(numBufs);
+
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        allBufs[i] = request.outputBuffers[i].buffer.getNativeHandle();
+        allBufIds[i] = request.outputBuffers[i].bufferId;
+        allBufPtrs[i] = &allBufs[i];
+        streamIds[i] = request.outputBuffers[i].streamId;
+    }
+
+    for (size_t i = 0; i < numBufs; i++) {
+        buffer_handle_t buf = allBufs[i];
+        uint64_t bufId = allBufIds[i];
+        CirculatingBuffers& cbs = mCirculatingBuffers[streamIds[i]];
+        if (cbs.count(bufId) == 0) {
+            if (buf == nullptr) {
+                ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+                return Status::ILLEGAL_ARGUMENT;
+            }
+            // Register a newly seen buffer
+            buffer_handle_t importedBuf = buf;
+            sHandleImporter.importBuffer(importedBuf);
+            if (importedBuf == nullptr) {
+                ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i);
+                return Status::INTERNAL_ERROR;
+            } else {
+                cbs[bufId] = importedBuf;
+            }
+        }
+        allBufPtrs[i] = &cbs[bufId];
+    }
+
+    // All buffers are imported. Now validate output buffer acquire fences
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        if (!sHandleImporter.importFence(
+                request.outputBuffers[i].acquireFence, allFences[i])) {
+            ALOGE("%s: output buffer %zu acquire fence is invalid", __FUNCTION__, i);
+            cleanupInflightFences(allFences, i);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+    return Status::OK;
+}
+
+void ExternalCameraDeviceSession::cleanupInflightFences(
+        hidl_vec<int>& allFences, size_t numFences) {
+    for (size_t j = 0; j < numFences; j++) {
+        sHandleImporter.closeFence(allFences[j]);
+    }
+}
+
+Status ExternalCameraDeviceSession::processOneCaptureRequest(const CaptureRequest& request)  {
+    Status status = initStatus();
+    if (status != Status::OK) {
+        return status;
+    }
+
+    if (request.inputBuffer.streamId != -1) {
+        ALOGE("%s: external camera does not support reprocessing!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    Mutex::Autolock _l(mLock);
+    if (!mV4l2Streaming) {
+        ALOGE("%s: cannot process request in streamOff state!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    const camera_metadata_t *rawSettings = nullptr;
+    bool converted = true;
+    CameraMetadata settingsFmq;  // settings from FMQ
+    if (request.fmqSettingsSize > 0) {
+        // non-blocking read; client must write metadata before calling
+        // processOneCaptureRequest
+        settingsFmq.resize(request.fmqSettingsSize);
+        bool read = mRequestMetadataQueue->read(settingsFmq.data(), request.fmqSettingsSize);
+        if (read) {
+            converted = V3_2::implementation::convertFromHidl(settingsFmq, &rawSettings);
+        } else {
+            ALOGE("%s: capture request settings metadata couldn't be read from fmq!", __FUNCTION__);
+            converted = false;
+        }
+    } else {
+        converted = V3_2::implementation::convertFromHidl(request.settings, &rawSettings);
+    }
+
+    if (converted && rawSettings != nullptr) {
+        mLatestReqSetting = rawSettings;
+    }
+
+    if (!converted) {
+        ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (mFirstRequest && rawSettings == nullptr) {
+        ALOGE("%s: capture request settings must not be null for first request!",
+                __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    hidl_vec<buffer_handle_t*> allBufPtrs;
+    hidl_vec<int> allFences;
+    size_t numOutputBufs = request.outputBuffers.size();
+
+    if (numOutputBufs == 0) {
+        ALOGE("%s: capture request must have at least one output buffer!", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    status = importRequest(request, allBufPtrs, allFences);
+    if (status != Status::OK) {
+        return status;
+    }
+
+    // TODO: program fps range per capture request here
+    //       or limit the set of availableFpsRange
+
+    sp<V4L2Frame> frameIn = dequeueV4l2FrameLocked();
+    if ( frameIn == nullptr) {
+        ALOGE("%s: V4L2 deque frame failed!", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+    // TODO: This can probably be replaced by use v4lbuffer timestamp
+    //       if the device supports it
+    nsecs_t shutterTs = systemTime(SYSTEM_TIME_MONOTONIC);
+
+
+    // TODO: reduce object copy in this path
+    HalRequest halReq = {
+            .frameNumber = request.frameNumber,
+            .setting = mLatestReqSetting,
+            .frameIn = frameIn,
+            .shutterTs = shutterTs};
+    halReq.buffers.resize(numOutputBufs);
+    for (size_t i = 0; i < numOutputBufs; i++) {
+        HalStreamBuffer& halBuf = halReq.buffers[i];
+        int streamId = halBuf.streamId = request.outputBuffers[i].streamId;
+        halBuf.bufferId = request.outputBuffers[i].bufferId;
+        const Stream& stream = mStreamMap[streamId];
+        halBuf.width = stream.width;
+        halBuf.height = stream.height;
+        halBuf.format = stream.format;
+        halBuf.usage = stream.usage;
+        halBuf.bufPtr = allBufPtrs[i];
+        halBuf.acquireFence = allFences[i];
+        halBuf.fenceTimeout = false;
+    }
+    mInflightFrames.insert(halReq.frameNumber);
+    // Send request to OutputThread for the rest of processing
+    mOutputThread->submitRequest(halReq);
+    mFirstRequest = false;
+    return Status::OK;
+}
+
+void ExternalCameraDeviceSession::notifyShutter(uint32_t frameNumber, nsecs_t shutterTs) {
+    NotifyMsg msg;
+    msg.type = MsgType::SHUTTER;
+    msg.msg.shutter.frameNumber = frameNumber;
+    msg.msg.shutter.timestamp = shutterTs;
+    mCallback->notify({msg});
+}
+
+void ExternalCameraDeviceSession::notifyError(
+        uint32_t frameNumber, int32_t streamId, ErrorCode ec) {
+    NotifyMsg msg;
+    msg.type = MsgType::ERROR;
+    msg.msg.error.frameNumber = frameNumber;
+    msg.msg.error.errorStreamId = streamId;
+    msg.msg.error.errorCode = ec;
+    mCallback->notify({msg});
+}
+
+//TODO: refactor with processCaptureResult
+Status ExternalCameraDeviceSession::processCaptureRequestError(HalRequest& req) {
+    // Return V4L2 buffer to V4L2 buffer queue
+    enqueueV4l2Frame(req.frameIn);
+
+    // NotifyShutter
+    notifyShutter(req.frameNumber, req.shutterTs);
+
+    notifyError(/*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+
+    // Fill output buffers
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    CaptureResult& result = results[0];
+    result.frameNumber = req.frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req.buffers.size());
+    for (size_t i = 0; i < req.buffers.size(); i++) {
+        result.outputBuffers[i].streamId = req.buffers[i].streamId;
+        result.outputBuffers[i].bufferId = req.buffers[i].bufferId;
+        result.outputBuffers[i].status = BufferStatus::ERROR;
+        if (req.buffers[i].acquireFence >= 0) {
+            native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+            handle->data[0] = req.buffers[i].acquireFence;
+            result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+        }
+    }
+
+    // update inflight records
+    {
+        Mutex::Autolock _l(mLock);
+        mInflightFrames.erase(req.frameNumber);
+    }
+
+    // Callback into framework
+    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+    freeReleaseFences(results);
+    return Status::OK;
+}
+
+Status ExternalCameraDeviceSession::processCaptureResult(HalRequest& req) {
+    // Return V4L2 buffer to V4L2 buffer queue
+    enqueueV4l2Frame(req.frameIn);
+
+    // NotifyShutter
+    notifyShutter(req.frameNumber, req.shutterTs);
+
+    // Fill output buffers
+    hidl_vec<CaptureResult> results;
+    results.resize(1);
+    CaptureResult& result = results[0];
+    result.frameNumber = req.frameNumber;
+    result.partialResult = 1;
+    result.inputBuffer.streamId = -1;
+    result.outputBuffers.resize(req.buffers.size());
+    for (size_t i = 0; i < req.buffers.size(); i++) {
+        result.outputBuffers[i].streamId = req.buffers[i].streamId;
+        result.outputBuffers[i].bufferId = req.buffers[i].bufferId;
+        if (req.buffers[i].fenceTimeout) {
+            result.outputBuffers[i].status = BufferStatus::ERROR;
+            native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+            handle->data[0] = req.buffers[i].acquireFence;
+            result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+            notifyError(req.frameNumber, req.buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+        } else {
+            result.outputBuffers[i].status = BufferStatus::OK;
+            // TODO: refactor
+            if (req.buffers[i].acquireFence > 0) {
+                native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+                handle->data[0] = req.buffers[i].acquireFence;
+                result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+            }
+        }
+    }
+
+    // Fill capture result metadata
+    fillCaptureResult(req.setting, req.shutterTs);
+    const camera_metadata_t *rawResult = req.setting.getAndLock();
+    V3_2::implementation::convertToHidl(rawResult, &result.result);
+    req.setting.unlock(rawResult);
+
+    // update inflight records
+    {
+        Mutex::Autolock _l(mLock);
+        mInflightFrames.erase(req.frameNumber);
+    }
+
+    // Callback into framework
+    invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+    freeReleaseFences(results);
+    return Status::OK;
+}
+
+void ExternalCameraDeviceSession::invokeProcessCaptureResultCallback(
+        hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+    if (mProcessCaptureResultLock.tryLock() != OK) {
+        const nsecs_t NS_TO_SECOND = 1000000000;
+        ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+        if (mProcessCaptureResultLock.timedLock(/* 1s */NS_TO_SECOND) != OK) {
+            ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+                    __FUNCTION__);
+            return;
+        }
+    }
+    if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+        for (CaptureResult &result : results) {
+            if (result.result.size() > 0) {
+                if (mResultMetadataQueue->write(result.result.data(), result.result.size())) {
+                    result.fmqResultSize = result.result.size();
+                    result.result.resize(0);
+                } else {
+                    ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+                    result.fmqResultSize = 0;
+                }
+            } else {
+                result.fmqResultSize = 0;
+            }
+        }
+    }
+    auto status = mCallback->processCaptureResult(results);
+    if (!status.isOk()) {
+        ALOGE("%s: processCaptureResult ERROR : %s", __FUNCTION__,
+              status.description().c_str());
+    }
+
+    mProcessCaptureResultLock.unlock();
+}
+
+void ExternalCameraDeviceSession::freeReleaseFences(hidl_vec<CaptureResult>& results) {
+    for (auto& result : results) {
+        if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+            native_handle_t* handle = const_cast<native_handle_t*>(
+                    result.inputBuffer.releaseFence.getNativeHandle());
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+        for (auto& buf : result.outputBuffers) {
+            if (buf.releaseFence.getNativeHandle() != nullptr) {
+                native_handle_t* handle = const_cast<native_handle_t*>(
+                        buf.releaseFence.getNativeHandle());
+                native_handle_close(handle);
+                native_handle_delete(handle);
+            }
+        }
+    }
+    return;
+}
+
+ExternalCameraDeviceSession::OutputThread::OutputThread(
+        wp<ExternalCameraDeviceSession> parent,
+        CroppingType ct) : mParent(parent), mCroppingType(ct) {}
+
+ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
+
+uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout(
+        const YCbCrLayout& layout) {
+    intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
+    intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
+    if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
+        // Interleaved format
+        if (layout.cb > layout.cr) {
+            return V4L2_PIX_FMT_NV21;
+        } else {
+            return V4L2_PIX_FMT_NV12;
+        }
+    } else if (layout.chromaStep == 1) {
+        // Planar format
+        if (layout.cb > layout.cr) {
+            return V4L2_PIX_FMT_YVU420; // YV12
+        } else {
+            return V4L2_PIX_FMT_YUV420; // YU12
+        }
+    } else {
+        return FLEX_YUV_GENERIC;
+    }
+}
+
+int ExternalCameraDeviceSession::OutputThread::getCropRect(
+        CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
+    if (out == nullptr) {
+        ALOGE("%s: out is null", __FUNCTION__);
+        return -1;
+    }
+
+    uint32_t inW = inSize.width;
+    uint32_t inH = inSize.height;
+    uint32_t outW = outSize.width;
+    uint32_t outH = outSize.height;
+
+    // Handle special case where aspect ratio is close to input but scaled
+    // dimension is slightly larger than input
+    float arIn = ASPECT_RATIO(inSize);
+    float arOut = ASPECT_RATIO(outSize);
+    if (isAspectRatioClose(arIn, arOut)) {
+        out->left = 0;
+        out->top = 0;
+        out->width = inW;
+        out->height = inH;
+        return 0;
+    }
+
+    if (ct == VERTICAL) {
+        uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
+        if (scaledOutH > inH) {
+            ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
+                    __FUNCTION__, outW, outH, inW, inH);
+            return -1;
+        }
+        scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
+
+        out->left = 0;
+        out->top = ((inH - scaledOutH) / 2) & ~0x1;
+        out->width = inW;
+        out->height = static_cast<int32_t>(scaledOutH);
+        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
+                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
+    } else {
+        uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
+        if (scaledOutW > inW) {
+            ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
+                    __FUNCTION__, outW, outH, inW, inH);
+            return -1;
+        }
+        scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
+
+        out->left = ((inW - scaledOutW) / 2) & ~0x1;
+        out->top = 0;
+        out->width = static_cast<int32_t>(scaledOutW);
+        out->height = inH;
+        ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
+                __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
+    }
+
+    return 0;
+}
+
+int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
+        sp<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
+    Size inSz = {in->mWidth, in->mHeight};
+
+    int ret;
+    if (inSz == outSz) {
+        ret = in->getLayout(out);
+        if (ret != 0) {
+            ALOGE("%s: failed to get input image layout", __FUNCTION__);
+            return ret;
+        }
+        return ret;
+    }
+
+    // Cropping to output aspect ratio
+    IMapper::Rect inputCrop;
+    ret = getCropRect(mCroppingType, inSz, outSz, &inputCrop);
+    if (ret != 0) {
+        ALOGE("%s: failed to compute crop rect for output size %dx%d",
+                __FUNCTION__, outSz.width, outSz.height);
+        return ret;
+    }
+
+    YCbCrLayout croppedLayout;
+    ret = in->getCroppedLayout(inputCrop, &croppedLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to crop input image %dx%d to output size %dx%d",
+                __FUNCTION__, inSz.width, inSz.height, outSz.width, outSz.height);
+        return ret;
+    }
+
+    if ((mCroppingType == VERTICAL && inSz.width == outSz.width) ||
+            (mCroppingType == HORIZONTAL && inSz.height == outSz.height)) {
+        // No scale is needed
+        *out = croppedLayout;
+        return 0;
+    }
+
+    auto it = mScaledYu12Frames.find(outSz);
+    sp<AllocatedFrame> scaledYu12Buf;
+    if (it != mScaledYu12Frames.end()) {
+        scaledYu12Buf = it->second;
+    } else {
+        it = mIntermediateBuffers.find(outSz);
+        if (it == mIntermediateBuffers.end()) {
+            ALOGE("%s: failed to find intermediate buffer size %dx%d",
+                    __FUNCTION__, outSz.width, outSz.height);
+            return -1;
+        }
+        scaledYu12Buf = it->second;
+    }
+    // Scale
+    YCbCrLayout outLayout;
+    ret = scaledYu12Buf->getLayout(&outLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to get output buffer layout", __FUNCTION__);
+        return ret;
+    }
+
+    ret = libyuv::I420Scale(
+            static_cast<uint8_t*>(croppedLayout.y),
+            croppedLayout.yStride,
+            static_cast<uint8_t*>(croppedLayout.cb),
+            croppedLayout.cStride,
+            static_cast<uint8_t*>(croppedLayout.cr),
+            croppedLayout.cStride,
+            inputCrop.width,
+            inputCrop.height,
+            static_cast<uint8_t*>(outLayout.y),
+            outLayout.yStride,
+            static_cast<uint8_t*>(outLayout.cb),
+            outLayout.cStride,
+            static_cast<uint8_t*>(outLayout.cr),
+            outLayout.cStride,
+            outSz.width,
+            outSz.height,
+            // TODO: b/72261744 see if we can use better filter without losing too much perf
+            libyuv::FilterMode::kFilterNone);
+
+    if (ret != 0) {
+        ALOGE("%s: failed to scale buffer from %dx%d to %dx%d. Ret %d",
+                __FUNCTION__, inputCrop.width, inputCrop.height,
+                outSz.width, outSz.height, ret);
+        return ret;
+    }
+
+    *out = outLayout;
+    mScaledYu12Frames.insert({outSz, scaledYu12Buf});
+    return 0;
+}
+
+
+int ExternalCameraDeviceSession::OutputThread::cropAndScaleThumbLocked(
+        sp<AllocatedFrame>& in, const Size &outSz, YCbCrLayout* out) {
+    Size inSz  {in->mWidth, in->mHeight};
+
+    if ((outSz.width * outSz.height) >
+        (mYu12ThumbFrame->mWidth * mYu12ThumbFrame->mHeight)) {
+        ALOGE("%s: Requested thumbnail size too big (%d,%d) > (%d,%d)",
+              __FUNCTION__, outSz.width, outSz.height,
+              mYu12ThumbFrame->mWidth, mYu12ThumbFrame->mHeight);
+        return -1;
+    }
+
+    int ret;
+
+    /* This will crop-and-zoom the input YUV frame to the thumbnail size
+     * Based on the following logic:
+     *  1) Square pixels come in, square pixels come out, therefore single
+     *  scale factor is computed to either make input bigger or smaller
+     *  depending on if we are upscaling or downscaling
+     *  2) That single scale factor would either make height too tall or width
+     *  too wide so we need to crop the input either horizontally or vertically
+     *  but not both
+     */
+
+    /* Convert the input and output dimensions into floats for ease of math */
+    float fWin = static_cast<float>(inSz.width);
+    float fHin = static_cast<float>(inSz.height);
+    float fWout = static_cast<float>(outSz.width);
+    float fHout = static_cast<float>(outSz.height);
+
+    /* Compute the one scale factor from (1) above, it will be the smaller of
+     * the two possibilities. */
+    float scaleFactor = std::min( fHin / fHout, fWin / fWout );
+
+    /* Since we are crop-and-zooming (as opposed to letter/pillar boxing) we can
+     * simply multiply the output by our scaleFactor to get the cropped input
+     * size. Note that at least one of {fWcrop, fHcrop} is going to wind up
+     * being {fWin, fHin} respectively because fHout or fWout cancels out the
+     * scaleFactor calculation above.
+     *
+     * Specifically:
+     *  if ( fHin / fHout ) < ( fWin / fWout ) we crop the sides off
+     * input, in which case
+     *    scaleFactor = fHin / fHout
+     *    fWcrop = fHin / fHout * fWout
+     *    fHcrop = fHin
+     *
+     * Note that fWcrop <= fWin ( because ( fHin / fHout ) * fWout < fWin, which
+     * is just the inequality above with both sides multiplied by fWout
+     *
+     * on the other hand if ( fWin / fWout ) < ( fHin / fHout) we crop the top
+     * and the bottom off of input, and
+     *    scaleFactor = fWin / fWout
+     *    fWcrop = fWin
+     *    fHCrop = fWin / fWout * fHout
+     */
+    float fWcrop = scaleFactor * fWout;
+    float fHcrop = scaleFactor * fHout;
+
+    /* Convert to integer and truncate to an even number */
+    Size cropSz = { 2*static_cast<uint32_t>(fWcrop/2.0f),
+                    2*static_cast<uint32_t>(fHcrop/2.0f) };
+
+    /* Convert to a centered rectange with even top/left */
+    IMapper::Rect inputCrop {
+        2*static_cast<int32_t>((inSz.width - cropSz.width)/4),
+        2*static_cast<int32_t>((inSz.height - cropSz.height)/4),
+        static_cast<int32_t>(cropSz.width),
+        static_cast<int32_t>(cropSz.height) };
+
+    if ((inputCrop.top < 0) ||
+        (inputCrop.top >= static_cast<int32_t>(inSz.height)) ||
+        (inputCrop.left < 0) ||
+        (inputCrop.left >= static_cast<int32_t>(inSz.width)) ||
+        (inputCrop.width <= 0) ||
+        (inputCrop.width + inputCrop.left > static_cast<int32_t>(inSz.width)) ||
+        (inputCrop.height <= 0) ||
+        (inputCrop.height + inputCrop.top > static_cast<int32_t>(inSz.height)))
+    {
+        ALOGE("%s: came up with really wrong crop rectangle",__FUNCTION__);
+        ALOGE("%s: input layout %dx%d to for output size %dx%d",
+             __FUNCTION__, inSz.width, inSz.height, outSz.width, outSz.height);
+        ALOGE("%s: computed input crop +%d,+%d %dx%d",
+             __FUNCTION__, inputCrop.left, inputCrop.top,
+             inputCrop.width, inputCrop.height);
+        return -1;
+    }
+
+    YCbCrLayout inputLayout;
+    ret = in->getCroppedLayout(inputCrop, &inputLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to crop input layout %dx%d to for output size %dx%d",
+             __FUNCTION__, inSz.width, inSz.height, outSz.width, outSz.height);
+        ALOGE("%s: computed input crop +%d,+%d %dx%d",
+             __FUNCTION__, inputCrop.left, inputCrop.top,
+             inputCrop.width, inputCrop.height);
+        return ret;
+    }
+    ALOGV("%s: crop input layout %dx%d to for output size %dx%d",
+          __FUNCTION__, inSz.width, inSz.height, outSz.width, outSz.height);
+    ALOGV("%s: computed input crop +%d,+%d %dx%d",
+          __FUNCTION__, inputCrop.left, inputCrop.top,
+          inputCrop.width, inputCrop.height);
+
+
+    // Scale
+    YCbCrLayout outFullLayout;
+
+    ret = mYu12ThumbFrame->getLayout(&outFullLayout);
+    if (ret != 0) {
+        ALOGE("%s: failed to get output buffer layout", __FUNCTION__);
+        return ret;
+    }
+
+
+    ret = libyuv::I420Scale(
+            static_cast<uint8_t*>(inputLayout.y),
+            inputLayout.yStride,
+            static_cast<uint8_t*>(inputLayout.cb),
+            inputLayout.cStride,
+            static_cast<uint8_t*>(inputLayout.cr),
+            inputLayout.cStride,
+            inputCrop.width,
+            inputCrop.height,
+            static_cast<uint8_t*>(outFullLayout.y),
+            outFullLayout.yStride,
+            static_cast<uint8_t*>(outFullLayout.cb),
+            outFullLayout.cStride,
+            static_cast<uint8_t*>(outFullLayout.cr),
+            outFullLayout.cStride,
+            outSz.width,
+            outSz.height,
+            libyuv::FilterMode::kFilterNone);
+
+    if (ret != 0) {
+        ALOGE("%s: failed to scale buffer from %dx%d to %dx%d. Ret %d",
+                __FUNCTION__, inputCrop.width, inputCrop.height,
+                outSz.width, outSz.height, ret);
+        return ret;
+    }
+
+    *out = outFullLayout;
+    return 0;
+}
+
+int ExternalCameraDeviceSession::OutputThread::formatConvertLocked(
+        const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
+    int ret = 0;
+    switch (format) {
+        case V4L2_PIX_FMT_NV21:
+            ret = libyuv::I420ToNV21(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cr),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: convert to NV21 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case V4L2_PIX_FMT_NV12:
+            ret = libyuv::I420ToNV12(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cb),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: convert to NV12 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case V4L2_PIX_FMT_YVU420: // YV12
+        case V4L2_PIX_FMT_YUV420: // YU12
+            // TODO: maybe we can speed up here by somehow save this copy?
+            ret = libyuv::I420Copy(
+                    static_cast<uint8_t*>(in.y),
+                    in.yStride,
+                    static_cast<uint8_t*>(in.cb),
+                    in.cStride,
+                    static_cast<uint8_t*>(in.cr),
+                    in.cStride,
+                    static_cast<uint8_t*>(out.y),
+                    out.yStride,
+                    static_cast<uint8_t*>(out.cb),
+                    out.cStride,
+                    static_cast<uint8_t*>(out.cr),
+                    out.cStride,
+                    sz.width,
+                    sz.height);
+            if (ret != 0) {
+                ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
+                            __FUNCTION__, ret);
+                return ret;
+            }
+            break;
+        case FLEX_YUV_GENERIC:
+            // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
+            ALOGE("%s: unsupported flexible yuv layout"
+                    " y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                    __FUNCTION__, out.y, out.cb, out.cr,
+                    out.yStride, out.cStride, out.chromaStep);
+            return -1;
+        default:
+            ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
+            return -1;
+    }
+    return 0;
+}
+
+int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12(
+        const Size & inSz, const YCbCrLayout& inLayout,
+        int jpegQuality, const void *app1Buffer, size_t app1Size,
+        void *out, const size_t maxOutSize, size_t &actualCodeSize)
+{
+    /* libjpeg is a C library so we use C-style "inheritance" by
+     * putting libjpeg's jpeg_destination_mgr first in our custom
+     * struct. This allows us to cast jpeg_destination_mgr* to
+     * CustomJpegDestMgr* when we get it passed to us in a callback */
+    struct CustomJpegDestMgr {
+        struct jpeg_destination_mgr mgr;
+        JOCTET *mBuffer;
+        size_t mBufferSize;
+        size_t mEncodedSize;
+        bool mSuccess;
+    } dmgr;
+
+    jpeg_compress_struct cinfo = {};
+    jpeg_error_mgr jerr;
+
+    /* Initialize error handling with standard callbacks, but
+     * then override output_message (to print to ALOG) and
+     * error_exit to set a flag and print a message instead
+     * of killing the whole process */
+    cinfo.err = jpeg_std_error(&jerr);
+
+    cinfo.err->output_message = [](j_common_ptr cinfo) {
+        char buffer[JMSG_LENGTH_MAX];
+
+        /* Create the message */
+        (*cinfo->err->format_message)(cinfo, buffer);
+        ALOGE("libjpeg error: %s", buffer);
+    };
+    cinfo.err->error_exit = [](j_common_ptr cinfo) {
+        (*cinfo->err->output_message)(cinfo);
+        if(cinfo->client_data) {
+            auto & dmgr =
+                *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+            dmgr.mSuccess = false;
+        }
+    };
+    /* Now that we initialized some callbacks, let's create our compressor */
+    jpeg_create_compress(&cinfo);
+
+    /* Initialize our destination manager */
+    dmgr.mBuffer = static_cast<JOCTET*>(out);
+    dmgr.mBufferSize = maxOutSize;
+    dmgr.mEncodedSize = 0;
+    dmgr.mSuccess = true;
+    cinfo.client_data = static_cast<void*>(&dmgr);
+
+    /* These lambdas become C-style function pointers and as per C++11 spec
+     * may not capture anything */
+    dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mgr.next_output_byte = dmgr.mBuffer;
+        dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+        ALOGV("%s:%d jpeg start: %p [%zu]",
+              __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+    };
+
+    dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+        ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+        return 0;
+    };
+
+    dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+        auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+        dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+        ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+    };
+    cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+    /* We are going to be using JPEG in raw data mode, so we are passing
+     * straight subsampled planar YCbCr and it will not touch our pixel
+     * data or do any scaling or anything */
+    cinfo.image_width = inSz.width;
+    cinfo.image_height = inSz.height;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_YCbCr;
+
+    /* Initialize defaults and then override what we want */
+    jpeg_set_defaults(&cinfo);
+
+    jpeg_set_quality(&cinfo, jpegQuality, 1);
+    jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+    cinfo.raw_data_in = 1;
+    cinfo.dct_method = JDCT_IFAST;
+
+    /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+     * because the source format is YUV420. Note that libjpeg sampling factors
+     * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+     * 1 V value for each 2 Y values */
+    cinfo.comp_info[0].h_samp_factor = 2;
+    cinfo.comp_info[0].v_samp_factor = 2;
+    cinfo.comp_info[1].h_samp_factor = 1;
+    cinfo.comp_info[1].v_samp_factor = 1;
+    cinfo.comp_info[2].h_samp_factor = 1;
+    cinfo.comp_info[2].v_samp_factor = 1;
+
+    /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+    int maxVSampFactor = std::max( {
+        cinfo.comp_info[0].v_samp_factor,
+        cinfo.comp_info[1].v_samp_factor,
+        cinfo.comp_info[2].v_samp_factor
+    });
+    int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
+                        cinfo.comp_info[1].v_samp_factor;
+
+    /* Start the compressor */
+    jpeg_start_compress(&cinfo, TRUE);
+
+    /* Compute our macroblock height, so we can pad our input to be vertically
+     * macroblock aligned.
+     * TODO: Does it need to be horizontally MCU aligned too? */
+
+    size_t mcuV = DCTSIZE*maxVSampFactor;
+    size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+    /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+     * data vertically (unfortunately doesn't help horizontally) */
+    std::vector<JSAMPROW> yLines (paddedHeight);
+    std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
+    std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
+
+    uint8_t *py = static_cast<uint8_t*>(inLayout.y);
+    uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
+    uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
+
+    for(uint32_t i = 0; i < paddedHeight; i++)
+    {
+        /* Once we are in the padding territory we still point to the last line
+         * effectively replicating it several times ~ CLAMP_TO_EDGE */
+        int li = std::min(i, inSz.height - 1);
+        yLines[i]  = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+        if(i < paddedHeight / cVSubSampling)
+        {
+            crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+            cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+        }
+    }
+
+    /* If APP1 data was passed in, use it */
+    if(app1Buffer && app1Size)
+    {
+        jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
+             static_cast<const JOCTET*>(app1Buffer), app1Size);
+    }
+
+    /* While we still have padded height left to go, keep giving it one
+     * macroblock at a time. */
+    while (cinfo.next_scanline < cinfo.image_height) {
+        const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+        const uint32_t nl = cinfo.next_scanline;
+        JSAMPARRAY planes[3]{ &yLines[nl],
+                              &cbLines[nl/cVSubSampling],
+                              &crLines[nl/cVSubSampling] };
+
+        uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+        if (done != batchSize) {
+            ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
+              __FUNCTION__, done, batchSize, cinfo.next_scanline,
+              cinfo.image_height);
+            return -1;
+        }
+    }
+
+    /* This will flush everything */
+    jpeg_finish_compress(&cinfo);
+
+    /* Grab the actual code size and set it */
+    actualCodeSize = dmgr.mEncodedSize;
+
+    return 0;
+}
+
+/*
+ * TODO: There needs to be a mechanism to discover allocated buffer size
+ * in the HAL.
+ *
+ * This is very fragile because it is duplicated computation from:
+ * frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
+ *
+ */
+
+/* This assumes mSupportedFormats have all been declared as supporting
+ * HAL_PIXEL_FORMAT_BLOB to the framework */
+Size ExternalCameraDeviceSession::getMaxJpegResolution() const {
+    Size ret { 0, 0 };
+    for(auto & fmt : mSupportedFormats) {
+        if(fmt.width * fmt.height > ret.width * ret.height) {
+            ret = Size { fmt.width, fmt.height };
+        }
+    }
+    return ret;
+}
+
+Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
+    Size thumbSize { 0, 0 };
+    camera_metadata_ro_entry entry =
+        mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for(uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+                  static_cast<uint32_t>(entry.data.i32[i+1]) };
+        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+    }
+
+    return thumbSize;
+}
+
+
+ssize_t ExternalCameraDeviceSession::getJpegBufferSize(
+        uint32_t width, uint32_t height) const {
+    // Constant from camera3.h
+    const ssize_t kMinJpegBufferSize = 256 * 1024 + sizeof(CameraBlob);
+    // Get max jpeg size (area-wise).
+    if (mMaxJpegResolution.width == 0) {
+        ALOGE("%s: Do not have a single supported JPEG stream",
+                __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    // Get max jpeg buffer size
+    ssize_t maxJpegBufferSize = 0;
+    camera_metadata_ro_entry jpegBufMaxSize =
+            mCameraCharacteristics.find(ANDROID_JPEG_MAX_SIZE);
+    if (jpegBufMaxSize.count == 0) {
+        ALOGE("%s: Can't find maximum JPEG size in static metadata!",
+              __FUNCTION__);
+        return BAD_VALUE;
+    }
+    maxJpegBufferSize = jpegBufMaxSize.data.i32[0];
+
+    if (maxJpegBufferSize <= kMinJpegBufferSize) {
+        ALOGE("%s: ANDROID_JPEG_MAX_SIZE (%zd) <= kMinJpegBufferSize (%zd)",
+              __FUNCTION__, maxJpegBufferSize, kMinJpegBufferSize);
+        return BAD_VALUE;
+    }
+
+    // Calculate final jpeg buffer size for the given resolution.
+    float scaleFactor = ((float) (width * height)) /
+            (mMaxJpegResolution.width * mMaxJpegResolution.height);
+    ssize_t jpegBufferSize = scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) +
+            kMinJpegBufferSize;
+    if (jpegBufferSize > maxJpegBufferSize) {
+        jpegBufferSize = maxJpegBufferSize;
+    }
+
+    return jpegBufferSize;
+}
+
+int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
+        HalStreamBuffer &halBuf,
+        HalRequest &req)
+{
+    int ret;
+    auto lfail = [&](auto... args) {
+        ALOGE(args...);
+
+        return 1;
+    };
+    auto parent = mParent.promote();
+    if (parent == nullptr) {
+       ALOGE("%s: session has been disconnected!", __FUNCTION__);
+       return 1;
+    }
+
+    ALOGV("%s: HAL buffer sid: %d bid: %" PRIu64 " w: %u h: %u",
+          __FUNCTION__, halBuf.streamId, static_cast<uint64_t>(halBuf.bufferId),
+          halBuf.width, halBuf.height);
+    ALOGV("%s: HAL buffer fmt: %x usage: %" PRIx64 " ptr: %p",
+          __FUNCTION__, halBuf.format, static_cast<uint64_t>(halBuf.usage),
+          halBuf.bufPtr);
+    ALOGV("%s: YV12 buffer %d x %d",
+          __FUNCTION__,
+          mYu12Frame->mWidth, mYu12Frame->mHeight);
+
+    int jpegQuality, thumbQuality;
+    Size thumbSize;
+
+    if (req.setting.exists(ANDROID_JPEG_QUALITY)) {
+        camera_metadata_entry entry =
+            req.setting.find(ANDROID_JPEG_QUALITY);
+        jpegQuality = entry.data.u8[0];
+    } else {
+        return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__);
+    }
+
+    if (req.setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+        camera_metadata_entry entry =
+            req.setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+        thumbQuality = entry.data.u8[0];
+    } else {
+        return lfail(
+            "%s: ANDROID_JPEG_THUMBNAIL_QUALITY not set",
+            __FUNCTION__);
+    }
+
+    if (req.setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+        camera_metadata_entry entry =
+            req.setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+        thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
+                           static_cast<uint32_t>(entry.data.i32[1])
+        };
+    } else {
+        return lfail(
+            "%s: ANDROID_JPEG_THUMBNAIL_SIZE not set", __FUNCTION__);
+    }
+
+    /* Cropped and scaled YU12 buffer for main and thumbnail */
+    YCbCrLayout yu12Main;
+    Size jpegSize { halBuf.width, halBuf.height };
+
+    /* Compute temporary buffer sizes accounting for the following:
+     * thumbnail can't exceed APP1 size of 64K
+     * main image needs to hold APP1, headers, and at most a poorly
+     * compressed image */
+    const ssize_t maxThumbCodeSize = 64 * 1024;
+    const ssize_t maxJpegCodeSize = parent->getJpegBufferSize(jpegSize.width,
+                                                             jpegSize.height);
+
+    /* Check that getJpegBufferSize did not return an error */
+    if (maxJpegCodeSize < 0) {
+        return lfail(
+            "%s: getJpegBufferSize returned %zd",__FUNCTION__,maxJpegCodeSize);
+    }
+
+
+    /* Hold actual thumbnail and main image code sizes */
+    size_t thumbCodeSize = 0, jpegCodeSize = 0;
+    /* Temporary thumbnail code buffer */
+    std::vector<uint8_t> thumbCode(maxThumbCodeSize);
+
+    YCbCrLayout yu12Thumb;
+    ret = cropAndScaleThumbLocked(mYu12Frame, thumbSize, &yu12Thumb);
+
+    if (ret != 0) {
+        return lfail(
+            "%s: crop and scale thumbnail failed!", __FUNCTION__);
+    }
+
+    /* Scale and crop main jpeg */
+    ret = cropAndScaleLocked(mYu12Frame, jpegSize, &yu12Main);
+
+    if (ret != 0) {
+        return lfail("%s: crop and scale main failed!", __FUNCTION__);
+    }
+
+    /* Encode the thumbnail image */
+    ret = encodeJpegYU12(thumbSize, yu12Thumb,
+            thumbQuality, 0, 0,
+            &thumbCode[0], maxThumbCodeSize, thumbCodeSize);
+
+    if (ret != 0) {
+        return lfail("%s: encodeJpegYU12 failed with %d",__FUNCTION__, ret);
+    }
+
+    /* Combine camera characteristics with request settings to form EXIF
+     * metadata */
+    common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics);
+    meta.append(req.setting);
+
+    /* Generate EXIF object */
+    std::unique_ptr<ExifUtils> utils(ExifUtils::create());
+    /* Make sure it's initialized */
+    utils->initialize();
+
+    utils->setFromMetadata(meta, jpegSize.width, jpegSize.height);
+
+    /* Check if we made a non-zero-sized thumbnail. Currently not possible
+     * that we got this far and the code is size 0, but if this code moves
+     * around it might become relevant again */
+
+    ret = utils->generateApp1(thumbCodeSize ? &thumbCode[0] : 0, thumbCodeSize);
+
+    if (!ret) {
+        return lfail("%s: generating APP1 failed", __FUNCTION__);
+    }
+
+    /* Get internal buffer */
+    size_t exifDataSize = utils->getApp1Length();
+    const uint8_t* exifData = utils->getApp1Buffer();
+
+    /* Lock the HAL jpeg code buffer */
+    void *bufPtr = sHandleImporter.lock(
+            *(halBuf.bufPtr), halBuf.usage, maxJpegCodeSize);
+
+    if (!bufPtr) {
+        return lfail("%s: could not lock %zu bytes", __FUNCTION__, maxJpegCodeSize);
+    }
+
+    /* Encode the main jpeg image */
+    ret = encodeJpegYU12(jpegSize, yu12Main,
+            jpegQuality, exifData, exifDataSize,
+            bufPtr, maxJpegCodeSize, jpegCodeSize);
+
+    /* TODO: Not sure this belongs here, maybe better to pass jpegCodeSize out
+     * and do this when returning buffer to parent */
+    CameraBlob blob { CameraBlobId::JPEG, static_cast<uint32_t>(jpegCodeSize) };
+    void *blobDst =
+        reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(bufPtr) +
+                           maxJpegCodeSize -
+                           sizeof(CameraBlob));
+    memcpy(blobDst, &blob, sizeof(CameraBlob));
+
+    /* Unlock the HAL jpeg code buffer */
+    int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+    if (relFence > 0) {
+        halBuf.acquireFence = relFence;
+    }
+
+    /* Check if our JPEG actually succeeded */
+    if (ret != 0) {
+        return lfail(
+            "%s: encodeJpegYU12 failed with %d",__FUNCTION__, ret);
+    }
+
+    ALOGV("%s: encoded JPEG (ret:%d) with Q:%d max size: %zu",
+          __FUNCTION__, ret, jpegQuality, maxJpegCodeSize);
+
+    return 0;
+}
+
+bool ExternalCameraDeviceSession::OutputThread::threadLoop() {
+    HalRequest req;
+    auto parent = mParent.promote();
+    if (parent == nullptr) {
+       ALOGE("%s: session has been disconnected!", __FUNCTION__);
+       return false;
+    }
+
+    // TODO: maybe we need to setup a sensor thread to dq/enq v4l frames
+    //       regularly to prevent v4l buffer queue filled with stale buffers
+    //       when app doesn't program a preveiw request
+    waitForNextRequest(&req);
+    if (req.frameIn == nullptr) {
+        // No new request, wait again
+        return true;
+    }
+
+    if (req.frameIn->mFourcc != V4L2_PIX_FMT_MJPEG) {
+        ALOGE("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+                req.frameIn->mFourcc & 0xFF,
+                (req.frameIn->mFourcc >> 8) & 0xFF,
+                (req.frameIn->mFourcc >> 16) & 0xFF,
+                (req.frameIn->mFourcc >> 24) & 0xFF);
+        parent->notifyError(
+                /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+        return false;
+    }
+
+    std::unique_lock<std::mutex> lk(mLock);
+
+    // Convert input V4L2 frame to YU12 of the same size
+    // TODO: see if we can save some computation by converting to YV12 here
+    uint8_t* inData;
+    size_t inDataSize;
+    req.frameIn->map(&inData, &inDataSize);
+    // TODO: profile
+    // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+    int res = libyuv::MJPGToI420(
+            inData, inDataSize,
+            static_cast<uint8_t*>(mYu12FrameLayout.y),
+            mYu12FrameLayout.yStride,
+            static_cast<uint8_t*>(mYu12FrameLayout.cb),
+            mYu12FrameLayout.cStride,
+            static_cast<uint8_t*>(mYu12FrameLayout.cr),
+            mYu12FrameLayout.cStride,
+            mYu12Frame->mWidth, mYu12Frame->mHeight,
+            mYu12Frame->mWidth, mYu12Frame->mHeight);
+
+    if (res != 0) {
+        // For some webcam, the first few V4L2 frames might be malformed...
+        ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
+        lk.unlock();
+        Status st = parent->processCaptureRequestError(req);
+        if (st != Status::OK) {
+            ALOGE("%s: failed to process capture request error!", __FUNCTION__);
+            parent->notifyError(
+                    /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+            return false;
+        }
+        return true;
+    }
+
+    ALOGV("%s processing new request", __FUNCTION__);
+    const int kSyncWaitTimeoutMs = 500;
+    for (auto& halBuf : req.buffers) {
+        if (halBuf.acquireFence != -1) {
+            int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+            if (ret) {
+                halBuf.fenceTimeout = true;
+            } else {
+                ::close(halBuf.acquireFence);
+                halBuf.acquireFence = -1;
+            }
+        }
+
+        if (halBuf.fenceTimeout) {
+            continue;
+        }
+
+        // Gralloc lockYCbCr the buffer
+        switch (halBuf.format) {
+            case PixelFormat::BLOB: {
+                int ret = createJpegLocked(halBuf, req);
+
+                if(ret != 0) {
+                    ALOGE("%s: createJpegLocked failed with %d",
+                          __FUNCTION__, ret);
+                    lk.unlock();
+                    parent->notifyError(
+                            /*frameNum*/req.frameNumber,
+                            /*stream*/-1,
+                            ErrorCode::ERROR_DEVICE);
+
+                    return false;
+                }
+            } break;
+            case PixelFormat::YCBCR_420_888:
+            case PixelFormat::YV12: {
+                IMapper::Rect outRect {0, 0,
+                        static_cast<int32_t>(halBuf.width),
+                        static_cast<int32_t>(halBuf.height)};
+                YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+                        *(halBuf.bufPtr), halBuf.usage, outRect);
+                ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
+                        __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
+                        outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
+
+                // Convert to output buffer size/format
+                uint32_t outputFourcc = getFourCcFromLayout(outLayout);
+                ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__,
+                        outputFourcc & 0xFF,
+                        (outputFourcc >> 8) & 0xFF,
+                        (outputFourcc >> 16) & 0xFF,
+                        (outputFourcc >> 24) & 0xFF);
+
+                YCbCrLayout cropAndScaled;
+                int ret = cropAndScaleLocked(
+                        mYu12Frame,
+                        Size { halBuf.width, halBuf.height },
+                        &cropAndScaled);
+                if (ret != 0) {
+                    ALOGE("%s: crop and scale failed!", __FUNCTION__);
+                    lk.unlock();
+                    parent->notifyError(
+                            /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+                    return false;
+                }
+
+                Size sz {halBuf.width, halBuf.height};
+                ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc);
+                if (ret != 0) {
+                    ALOGE("%s: format coversion failed!", __FUNCTION__);
+                    lk.unlock();
+                    parent->notifyError(
+                            /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+                    return false;
+                }
+                int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+                if (relFence > 0) {
+                    halBuf.acquireFence = relFence;
+                }
+            } break;
+            default:
+                ALOGE("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+                lk.unlock();
+                parent->notifyError(
+                        /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+                return false;
+        }
+    } // for each buffer
+    mScaledYu12Frames.clear();
+
+    // Don't hold the lock while calling back to parent
+    lk.unlock();
+    Status st = parent->processCaptureResult(req);
+    if (st != Status::OK) {
+        ALOGE("%s: failed to process capture result!", __FUNCTION__);
+        parent->notifyError(
+                /*frameNum*/req.frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+        return false;
+    }
+    return true;
+}
+
+Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers(
+        const Size& v4lSize, const Size& thumbSize,
+        const hidl_vec<Stream>& streams) {
+    std::lock_guard<std::mutex> lk(mLock);
+    if (mScaledYu12Frames.size() != 0) {
+        ALOGE("%s: intermediate buffer pool has %zu inflight buffers! (expect 0)",
+                __FUNCTION__, mScaledYu12Frames.size());
+        return Status::INTERNAL_ERROR;
+    }
+
+    // Allocating intermediate YU12 frame
+    if (mYu12Frame == nullptr || mYu12Frame->mWidth != v4lSize.width ||
+            mYu12Frame->mHeight != v4lSize.height) {
+        mYu12Frame.clear();
+        mYu12Frame = new AllocatedFrame(v4lSize.width, v4lSize.height);
+        int ret = mYu12Frame->allocate(&mYu12FrameLayout);
+        if (ret != 0) {
+            ALOGE("%s: allocating YU12 frame failed!", __FUNCTION__);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+
+    // Allocating intermediate YU12 thumbnail frame
+    if (mYu12ThumbFrame == nullptr ||
+        mYu12ThumbFrame->mWidth != thumbSize.width ||
+        mYu12ThumbFrame->mHeight != thumbSize.height) {
+        mYu12ThumbFrame.clear();
+        mYu12ThumbFrame = new AllocatedFrame(thumbSize.width, thumbSize.height);
+        int ret = mYu12ThumbFrame->allocate(&mYu12ThumbFrameLayout);
+        if (ret != 0) {
+            ALOGE("%s: allocating YU12 thumb frame failed!", __FUNCTION__);
+            return Status::INTERNAL_ERROR;
+        }
+    }
+
+    // Allocating scaled buffers
+    for (const auto& stream : streams) {
+        Size sz = {stream.width, stream.height};
+        if (sz == v4lSize) {
+            continue; // Don't need an intermediate buffer same size as v4lBuffer
+        }
+        if (mIntermediateBuffers.count(sz) == 0) {
+            // Create new intermediate buffer
+            sp<AllocatedFrame> buf = new AllocatedFrame(stream.width, stream.height);
+            int ret = buf->allocate();
+            if (ret != 0) {
+                ALOGE("%s: allocating intermediate YU12 frame %dx%d failed!",
+                            __FUNCTION__, stream.width, stream.height);
+                return Status::INTERNAL_ERROR;
+            }
+            mIntermediateBuffers[sz] = buf;
+        }
+    }
+
+    // Remove unconfigured buffers
+    auto it = mIntermediateBuffers.begin();
+    while (it != mIntermediateBuffers.end()) {
+        bool configured = false;
+        auto sz = it->first;
+        for (const auto& stream : streams) {
+            if (stream.width == sz.width && stream.height == sz.height) {
+                configured = true;
+                break;
+            }
+        }
+        if (configured) {
+            it++;
+        } else {
+            it = mIntermediateBuffers.erase(it);
+        }
+    }
+    return Status::OK;
+}
+
+Status ExternalCameraDeviceSession::OutputThread::submitRequest(const HalRequest& req) {
+    std::lock_guard<std::mutex> lk(mLock);
+    // TODO: reduce object copy in this path
+    mRequestList.push_back(req);
+    mRequestCond.notify_one();
+    return Status::OK;
+}
+
+void ExternalCameraDeviceSession::OutputThread::flush() {
+    std::lock_guard<std::mutex> lk(mLock);
+    // TODO: send buffer/request errors back to framework
+    mRequestList.clear();
+}
+
+void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(HalRequest* out) {
+    if (out == nullptr) {
+        ALOGE("%s: out is null", __FUNCTION__);
+        return;
+    }
+
+    std::unique_lock<std::mutex> lk(mLock);
+    while (mRequestList.empty()) {
+        std::chrono::seconds timeout = std::chrono::seconds(kReqWaitTimeoutSec);
+        auto st = mRequestCond.wait_for(lk, timeout);
+        if (st == std::cv_status::timeout) {
+            // no new request, return
+            return;
+        }
+    }
+    *out = mRequestList.front();
+    mRequestList.pop_front();
+}
+
+void ExternalCameraDeviceSession::cleanupBuffersLocked(int id) {
+    for (auto& pair : mCirculatingBuffers.at(id)) {
+        sHandleImporter.freeBuffer(pair.second);
+    }
+    mCirculatingBuffers[id].clear();
+    mCirculatingBuffers.erase(id);
+}
+
+void ExternalCameraDeviceSession::updateBufferCaches(const hidl_vec<BufferCache>& cachesToRemove) {
+    Mutex::Autolock _l(mLock);
+    for (auto& cache : cachesToRemove) {
+        auto cbsIt = mCirculatingBuffers.find(cache.streamId);
+        if (cbsIt == mCirculatingBuffers.end()) {
+            // The stream could have been removed
+            continue;
+        }
+        CirculatingBuffers& cbs = cbsIt->second;
+        auto it = cbs.find(cache.bufferId);
+        if (it != cbs.end()) {
+            sHandleImporter.freeBuffer(it->second);
+            cbs.erase(it);
+        } else {
+            ALOGE("%s: stream %d buffer %" PRIu64 " is not cached",
+                    __FUNCTION__, cache.streamId, cache.bufferId);
+        }
+    }
+}
+
+bool ExternalCameraDeviceSession::isSupported(const Stream& stream) {
+    int32_t ds = static_cast<int32_t>(stream.dataSpace);
+    PixelFormat fmt = stream.format;
+    uint32_t width = stream.width;
+    uint32_t height = stream.height;
+    // TODO: check usage flags
+
+    if (stream.streamType != StreamType::OUTPUT) {
+        ALOGE("%s: does not support non-output stream type", __FUNCTION__);
+        return false;
+    }
+
+    if (stream.rotation != StreamRotation::ROTATION_0) {
+        ALOGE("%s: does not support stream rotation", __FUNCTION__);
+        return false;
+    }
+
+    if (ds & Dataspace::DEPTH) {
+        ALOGI("%s: does not support depth output", __FUNCTION__);
+        return false;
+    }
+
+    switch (fmt) {
+        case PixelFormat::BLOB:
+            if (ds != static_cast<int32_t>(Dataspace::V0_JFIF)) {
+                ALOGI("%s: BLOB format does not support dataSpace %x", __FUNCTION__, ds);
+                return false;
+            }
+        case PixelFormat::IMPLEMENTATION_DEFINED:
+        case PixelFormat::YCBCR_420_888:
+        case PixelFormat::YV12:
+            // TODO: check what dataspace we can support here.
+            // intentional no-ops.
+            break;
+        default:
+            ALOGI("%s: does not support format %x", __FUNCTION__, fmt);
+            return false;
+    }
+
+    // Assume we can convert any V4L2 format to any of supported output format for now, i.e,
+    // ignoring v4l2Fmt.fourcc for now. Might need more subtle check if we support more v4l format
+    // in the futrue.
+    for (const auto& v4l2Fmt : mSupportedFormats) {
+        if (width == v4l2Fmt.width && height == v4l2Fmt.height) {
+            return true;
+        }
+    }
+    ALOGI("%s: resolution %dx%d is not supported", __FUNCTION__, width, height);
+    return false;
+}
+
+int ExternalCameraDeviceSession::v4l2StreamOffLocked() {
+    if (!mV4l2Streaming) {
+        return OK;
+    }
+
+    {
+        std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+        if (mNumDequeuedV4l2Buffers != 0)  {
+            ALOGE("%s: there are %zu inflight V4L buffers",
+                __FUNCTION__, mNumDequeuedV4l2Buffers);
+            return -1;
+        }
+    }
+    mV4L2BufferCount = 0;
+
+    // VIDIOC_STREAMOFF
+    v4l2_buf_type capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_STREAMOFF, &capture_type)) < 0) {
+        ALOGE("%s: STREAMOFF failed: %s", __FUNCTION__, strerror(errno));
+        return -errno;
+    }
+
+    // VIDIOC_REQBUFS: clear buffers
+    v4l2_requestbuffers req_buffers{};
+    req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    req_buffers.memory = V4L2_MEMORY_MMAP;
+    req_buffers.count = 0;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_REQBUFS, &req_buffers)) < 0) {
+        ALOGE("%s: REQBUFS failed: %s", __FUNCTION__, strerror(errno));
+        return -errno;
+    }
+
+    mV4l2Streaming = false;
+    return OK;
+}
+
+int ExternalCameraDeviceSession::configureV4l2StreamLocked(const SupportedV4L2Format& v4l2Fmt) {
+    int ret = v4l2StreamOffLocked();
+    if (ret != OK) {
+        ALOGE("%s: stop v4l2 streaming failed: ret %d", __FUNCTION__, ret);
+        return ret;
+    }
+
+    // VIDIOC_S_FMT w/h/fmt
+    v4l2_format fmt;
+    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    fmt.fmt.pix.width = v4l2Fmt.width;
+    fmt.fmt.pix.height = v4l2Fmt.height;
+    fmt.fmt.pix.pixelformat = v4l2Fmt.fourcc;
+    ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_FMT, &fmt));
+    if (ret < 0) {
+        ALOGE("%s: S_FMT ioctl failed: %s", __FUNCTION__, strerror(errno));
+        return -errno;
+    }
+
+    if (v4l2Fmt.width != fmt.fmt.pix.width || v4l2Fmt.height != fmt.fmt.pix.height ||
+            v4l2Fmt.fourcc != fmt.fmt.pix.pixelformat) {
+        ALOGE("%s: S_FMT expect %c%c%c%c %dx%d, got %c%c%c%c %dx%d instead!", __FUNCTION__,
+                v4l2Fmt.fourcc & 0xFF,
+                (v4l2Fmt.fourcc >> 8) & 0xFF,
+                (v4l2Fmt.fourcc >> 16) & 0xFF,
+                (v4l2Fmt.fourcc >> 24) & 0xFF,
+                v4l2Fmt.width, v4l2Fmt.height,
+                fmt.fmt.pix.pixelformat & 0xFF,
+                (fmt.fmt.pix.pixelformat >> 8) & 0xFF,
+                (fmt.fmt.pix.pixelformat >> 16) & 0xFF,
+                (fmt.fmt.pix.pixelformat >> 24) & 0xFF,
+                fmt.fmt.pix.width, fmt.fmt.pix.height);
+        return -EINVAL;
+    }
+    uint32_t bufferSize = fmt.fmt.pix.sizeimage;
+    ALOGI("%s: V4L2 buffer size is %d", __FUNCTION__, bufferSize);
+
+    float maxFps = -1.f;
+    float fps = 1000.f;
+    const float kDefaultFps = 30.f;
+    // Try to pick the slowest fps that is at least 30
+    for (const auto& f : v4l2Fmt.frameRates) {
+        if (maxFps < f) {
+            maxFps = f;
+        }
+        if (f >= kDefaultFps && f < fps) {
+            fps = f;
+        }
+    }
+    if (fps == 1000.f) {
+        fps = maxFps;
+    }
+
+    // VIDIOC_G_PARM/VIDIOC_S_PARM: set fps
+    v4l2_streamparm streamparm = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
+    // The following line checks that the driver knows about framerate get/set.
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_G_PARM, &streamparm)) >= 0) {
+        // Now check if the device is able to accept a capture framerate set.
+        if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
+            // |frame_rate| is float, approximate by a fraction.
+            const int kFrameRatePrecision = 10000;
+            streamparm.parm.capture.timeperframe.numerator = kFrameRatePrecision;
+            streamparm.parm.capture.timeperframe.denominator =
+                (fps * kFrameRatePrecision);
+
+            if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_PARM, &streamparm)) < 0) {
+                ALOGE("%s: failed to set framerate to %f", __FUNCTION__, fps);
+                return UNKNOWN_ERROR;
+            }
+        }
+    }
+    float retFps = streamparm.parm.capture.timeperframe.denominator /
+                streamparm.parm.capture.timeperframe.numerator;
+    if (std::fabs(fps - retFps) > std::numeric_limits<float>::epsilon()) {
+        ALOGE("%s: expect fps %f, got %f instead", __FUNCTION__, fps, retFps);
+        return BAD_VALUE;
+    }
+
+    uint32_t v4lBufferCount = (fps >= kDefaultFps) ?
+            mCfg.numVideoBuffers : mCfg.numStillBuffers;
+    // VIDIOC_REQBUFS: create buffers
+    v4l2_requestbuffers req_buffers{};
+    req_buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    req_buffers.memory = V4L2_MEMORY_MMAP;
+    req_buffers.count = v4lBufferCount;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_REQBUFS, &req_buffers)) < 0) {
+        ALOGE("%s: VIDIOC_REQBUFS failed: %s", __FUNCTION__, strerror(errno));
+        return -errno;
+    }
+
+    // Driver can indeed return more buffer if it needs more to operate
+    if (req_buffers.count < v4lBufferCount) {
+        ALOGE("%s: VIDIOC_REQBUFS expected %d buffers, got %d instead",
+                __FUNCTION__, v4lBufferCount, req_buffers.count);
+        return NO_MEMORY;
+    }
+
+    // VIDIOC_QUERYBUF:  get buffer offset in the V4L2 fd
+    // VIDIOC_QBUF: send buffer to driver
+    mV4L2BufferCount = req_buffers.count;
+    for (uint32_t i = 0; i < req_buffers.count; i++) {
+        v4l2_buffer buffer = {
+            .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+            .index = i,
+            .memory = V4L2_MEMORY_MMAP};
+
+        if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
+            ALOGE("%s: QUERYBUF %d failed: %s", __FUNCTION__, i,  strerror(errno));
+            return -errno;
+        }
+
+        if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
+            ALOGE("%s: QBUF %d failed: %s", __FUNCTION__, i,  strerror(errno));
+            return -errno;
+        }
+    }
+
+    // VIDIOC_STREAMON: start streaming
+    v4l2_buf_type capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_STREAMON, &capture_type)) < 0) {
+        ALOGE("%s: VIDIOC_STREAMON failed: %s", __FUNCTION__, strerror(errno));
+        return -errno;
+    }
+
+    // Swallow first few frames after streamOn to account for bad frames from some devices
+    for (int i = 0; i < kBadFramesAfterStreamOn; i++) {
+        v4l2_buffer buffer{};
+        buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        buffer.memory = V4L2_MEMORY_MMAP;
+        if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_DQBUF, &buffer)) < 0) {
+            ALOGE("%s: DQBUF fails: %s", __FUNCTION__, strerror(errno));
+            return -errno;
+        }
+
+        if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
+            ALOGE("%s: QBUF index %d fails: %s", __FUNCTION__, buffer.index, strerror(errno));
+            return -errno;
+        }
+    }
+
+    mV4l2StreamingFmt = v4l2Fmt;
+    mV4l2Streaming = true;
+    return OK;
+}
+
+sp<V4L2Frame> ExternalCameraDeviceSession::dequeueV4l2FrameLocked() {
+    sp<V4L2Frame> ret = nullptr;
+
+    {
+        std::unique_lock<std::mutex> lk(mV4l2BufferLock);
+        if (mNumDequeuedV4l2Buffers == mV4L2BufferCount) {
+            std::chrono::seconds timeout = std::chrono::seconds(kBufferWaitTimeoutSec);
+            mLock.unlock();
+            auto st = mV4L2BufferReturned.wait_for(lk, timeout);
+            mLock.lock();
+            if (st == std::cv_status::timeout) {
+                ALOGE("%s: wait for V4L2 buffer return timeout!", __FUNCTION__);
+                return ret;
+            }
+        }
+    }
+
+    v4l2_buffer buffer{};
+    buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    buffer.memory = V4L2_MEMORY_MMAP;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_DQBUF, &buffer)) < 0) {
+        ALOGE("%s: DQBUF fails: %s", __FUNCTION__, strerror(errno));
+        return ret;
+    }
+
+    if (buffer.index >= mV4L2BufferCount) {
+        ALOGE("%s: Invalid buffer id: %d", __FUNCTION__, buffer.index);
+        return ret;
+    }
+
+    if (buffer.flags & V4L2_BUF_FLAG_ERROR) {
+        ALOGE("%s: v4l2 buf error! buf flag 0x%x", __FUNCTION__, buffer.flags);
+        // TODO: try to dequeue again
+    }
+
+    {
+        std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+        mNumDequeuedV4l2Buffers++;
+    }
+    return new V4L2Frame(
+            mV4l2StreamingFmt.width, mV4l2StreamingFmt.height, mV4l2StreamingFmt.fourcc,
+            buffer.index, mV4l2Fd.get(), buffer.bytesused, buffer.m.offset);
+}
+
+void ExternalCameraDeviceSession::enqueueV4l2Frame(const sp<V4L2Frame>& frame) {
+    Mutex::Autolock _l(mLock);
+    frame->unmap();
+    v4l2_buffer buffer{};
+    buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+    buffer.memory = V4L2_MEMORY_MMAP;
+    buffer.index = frame->mBufferIndex;
+    if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {
+        ALOGE("%s: QBUF index %d fails: %s", __FUNCTION__, frame->mBufferIndex, strerror(errno));
+        return;
+    }
+
+    {
+        std::lock_guard<std::mutex> lk(mV4l2BufferLock);
+        mNumDequeuedV4l2Buffers--;
+        mV4L2BufferReturned.notify_one();
+    }
+}
+
+Status ExternalCameraDeviceSession::configureStreams(
+        const V3_2::StreamConfiguration& config, V3_3::HalStreamConfiguration* out) {
+    if (config.operationMode != StreamConfigurationMode::NORMAL_MODE) {
+        ALOGE("%s: unsupported operation mode: %d", __FUNCTION__, config.operationMode);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (config.streams.size() == 0) {
+        ALOGE("%s: cannot configure zero stream", __FUNCTION__);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    int numProcessedStream = 0;
+    int numStallStream = 0;
+    for (const auto& stream : config.streams) {
+        // Check if the format/width/height combo is supported
+        if (!isSupported(stream)) {
+            return Status::ILLEGAL_ARGUMENT;
+        }
+        if (stream.format == PixelFormat::BLOB) {
+            numStallStream++;
+        } else {
+            numProcessedStream++;
+        }
+    }
+
+    if (numProcessedStream > kMaxProcessedStream) {
+        ALOGE("%s: too many processed streams (expect <= %d, got %d)", __FUNCTION__,
+                kMaxProcessedStream, numProcessedStream);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (numStallStream > kMaxStallStream) {
+        ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__,
+                kMaxStallStream, numStallStream);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    Status status = initStatus();
+    if (status != Status::OK) {
+        return status;
+    }
+
+    Mutex::Autolock _l(mLock);
+    if (!mInflightFrames.empty()) {
+        ALOGE("%s: trying to configureStreams while there are still %zu inflight frames!",
+                __FUNCTION__, mInflightFrames.size());
+        return Status::INTERNAL_ERROR;
+    }
+
+    // Add new streams
+    for (const auto& stream : config.streams) {
+        if (mStreamMap.count(stream.id) == 0) {
+            mStreamMap[stream.id] = stream;
+            mCirculatingBuffers.emplace(stream.id, CirculatingBuffers{});
+        }
+    }
+
+    // Cleanup removed streams
+    for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+        int id = it->first;
+        bool found = false;
+        for (const auto& stream : config.streams) {
+            if (id == stream.id) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            // Unmap all buffers of deleted stream
+            cleanupBuffersLocked(id);
+            it = mStreamMap.erase(it);
+        } else {
+            ++it;
+        }
+    }
+
+    // Now select a V4L2 format to produce all output streams
+    float desiredAr = (mCroppingType == VERTICAL) ? kMaxAspectRatio : kMinAspectRatio;
+    uint32_t maxDim = 0;
+    for (const auto& stream : config.streams) {
+        float aspectRatio = ASPECT_RATIO(stream);
+        if ((mCroppingType == VERTICAL && aspectRatio < desiredAr) ||
+                (mCroppingType == HORIZONTAL && aspectRatio > desiredAr)) {
+            desiredAr = aspectRatio;
+        }
+
+        // The dimension that's not cropped
+        uint32_t dim = (mCroppingType == VERTICAL) ? stream.width : stream.height;
+        if (dim > maxDim) {
+            maxDim = dim;
+        }
+    }
+    // Find the smallest format that matches the desired aspect ratio and is wide/high enough
+    SupportedV4L2Format v4l2Fmt {.width = 0, .height = 0};
+    for (const auto& fmt : mSupportedFormats) {
+        uint32_t dim = (mCroppingType == VERTICAL) ? fmt.width : fmt.height;
+        if (dim >= maxDim) {
+            float aspectRatio = ASPECT_RATIO(fmt);
+            if (isAspectRatioClose(aspectRatio, desiredAr)) {
+                v4l2Fmt = fmt;
+                // since mSupportedFormats is sorted by width then height, the first matching fmt
+                // will be the smallest one with matching aspect ratio
+                break;
+            }
+        }
+    }
+    if (v4l2Fmt.width == 0) {
+        // Cannot find exact good aspect ratio candidate, try to find a close one
+        for (const auto& fmt : mSupportedFormats) {
+            uint32_t dim = (mCroppingType == VERTICAL) ? fmt.width : fmt.height;
+            if (dim >= maxDim) {
+                float aspectRatio = ASPECT_RATIO(fmt);
+                if ((mCroppingType == VERTICAL && aspectRatio < desiredAr) ||
+                        (mCroppingType == HORIZONTAL && aspectRatio > desiredAr)) {
+                    v4l2Fmt = fmt;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (v4l2Fmt.width == 0) {
+        ALOGE("%s: unable to find a resolution matching (%s at least %d, aspect ratio %f)"
+                , __FUNCTION__, (mCroppingType == VERTICAL) ? "width" : "height",
+                maxDim, desiredAr);
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    if (configureV4l2StreamLocked(v4l2Fmt) != 0) {
+        ALOGE("V4L configuration failed!, format:%c%c%c%c, w %d, h %d",
+            v4l2Fmt.fourcc & 0xFF,
+            (v4l2Fmt.fourcc >> 8) & 0xFF,
+            (v4l2Fmt.fourcc >> 16) & 0xFF,
+            (v4l2Fmt.fourcc >> 24) & 0xFF,
+            v4l2Fmt.width, v4l2Fmt.height);
+        return Status::INTERNAL_ERROR;
+    }
+
+    Size v4lSize = {v4l2Fmt.width, v4l2Fmt.height};
+    Size thumbSize { 0, 0 };
+    camera_metadata_ro_entry entry =
+        mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+    for(uint32_t i = 0; i < entry.count; i += 2) {
+        Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+                  static_cast<uint32_t>(entry.data.i32[i+1]) };
+        if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+            thumbSize = sz;
+        }
+    }
+
+    if (thumbSize.width * thumbSize.height == 0) {
+        ALOGE("%s: non-zero thumbnail size not available", __FUNCTION__);
+        return Status::INTERNAL_ERROR;
+    }
+
+    status = mOutputThread->allocateIntermediateBuffers(v4lSize,
+                mMaxThumbResolution, config.streams);
+    if (status != Status::OK) {
+        ALOGE("%s: allocating intermediate buffers failed!", __FUNCTION__);
+        return status;
+    }
+
+    out->streams.resize(config.streams.size());
+    for (size_t i = 0; i < config.streams.size(); i++) {
+        out->streams[i].overrideDataSpace = config.streams[i].dataSpace;
+        out->streams[i].v3_2.id = config.streams[i].id;
+        // TODO: double check should we add those CAMERA flags
+        mStreamMap[config.streams[i].id].usage =
+                out->streams[i].v3_2.producerUsage = config.streams[i].usage |
+                BufferUsage::CPU_WRITE_OFTEN |
+                BufferUsage::CAMERA_OUTPUT;
+        out->streams[i].v3_2.consumerUsage = 0;
+        out->streams[i].v3_2.maxBuffers  = mV4L2BufferCount;
+
+        switch (config.streams[i].format) {
+            case PixelFormat::BLOB:
+            case PixelFormat::YCBCR_420_888:
+            case PixelFormat::YV12: // Used by SurfaceTexture
+                // No override
+                out->streams[i].v3_2.overrideFormat = config.streams[i].format;
+                break;
+            case PixelFormat::IMPLEMENTATION_DEFINED:
+                // Override based on VIDEO or not
+                out->streams[i].v3_2.overrideFormat =
+                        (config.streams[i].usage & BufferUsage::VIDEO_ENCODER) ?
+                        PixelFormat::YCBCR_420_888 : PixelFormat::YV12;
+                // Save overridden formt in mStreamMap
+                mStreamMap[config.streams[i].id].format = out->streams[i].v3_2.overrideFormat;
+                break;
+            default:
+                ALOGE("%s: unsupported format 0x%x", __FUNCTION__, config.streams[i].format);
+                return Status::ILLEGAL_ARGUMENT;
+        }
+    }
+
+    mFirstRequest = true;
+    return Status::OK;
+}
+
+bool ExternalCameraDeviceSession::isClosed() {
+    Mutex::Autolock _l(mLock);
+    return mClosed;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define UPDATE(md, tag, data, size)               \
+do {                                              \
+    if ((md).update((tag), (data), (size))) {     \
+        ALOGE("Update " #tag " failed!");         \
+        return BAD_VALUE;                         \
+    }                                             \
+} while (0)
+
+status_t ExternalCameraDeviceSession::initDefaultRequests() {
+    ::android::hardware::camera::common::V1_0::helper::CameraMetadata md;
+
+    const uint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;
+    UPDATE(md, ANDROID_COLOR_CORRECTION_ABERRATION_MODE, &aberrationMode, 1);
+
+    const int32_t exposureCompensation = 0;
+    UPDATE(md, ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, &exposureCompensation, 1);
+
+    const uint8_t videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
+    UPDATE(md, ANDROID_CONTROL_VIDEO_STABILIZATION_MODE, &videoStabilizationMode, 1);
+
+    const uint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
+    UPDATE(md, ANDROID_CONTROL_AWB_MODE, &awbMode, 1);
+
+    const uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
+    UPDATE(md, ANDROID_CONTROL_AE_MODE, &aeMode, 1);
+
+    const uint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;
+    UPDATE(md, ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, &aePrecaptureTrigger, 1);
+
+    const uint8_t afMode = ANDROID_CONTROL_AF_MODE_AUTO;
+    UPDATE(md, ANDROID_CONTROL_AF_MODE, &afMode, 1);
+
+    const uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
+    UPDATE(md, ANDROID_CONTROL_AF_TRIGGER, &afTrigger, 1);
+
+    const uint8_t sceneMode = ANDROID_CONTROL_SCENE_MODE_DISABLED;
+    UPDATE(md, ANDROID_CONTROL_SCENE_MODE, &sceneMode, 1);
+
+    const uint8_t effectMode = ANDROID_CONTROL_EFFECT_MODE_OFF;
+    UPDATE(md, ANDROID_CONTROL_EFFECT_MODE, &effectMode, 1);
+
+    const uint8_t flashMode = ANDROID_FLASH_MODE_OFF;
+    UPDATE(md, ANDROID_FLASH_MODE, &flashMode, 1);
+
+    const int32_t thumbnailSize[] = {240, 180};
+    UPDATE(md, ANDROID_JPEG_THUMBNAIL_SIZE, thumbnailSize, 2);
+
+    const uint8_t jpegQuality = 90;
+    UPDATE(md, ANDROID_JPEG_QUALITY, &jpegQuality, 1);
+    UPDATE(md, ANDROID_JPEG_THUMBNAIL_QUALITY, &jpegQuality, 1);
+
+    const int32_t jpegOrientation = 0;
+    UPDATE(md, ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1);
+
+    const uint8_t oisMode = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;
+    UPDATE(md, ANDROID_LENS_OPTICAL_STABILIZATION_MODE, &oisMode, 1);
+
+    const uint8_t nrMode = ANDROID_NOISE_REDUCTION_MODE_OFF;
+    UPDATE(md, ANDROID_NOISE_REDUCTION_MODE, &nrMode, 1);
+
+    const uint8_t fdMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
+    UPDATE(md, ANDROID_STATISTICS_FACE_DETECT_MODE, &fdMode, 1);
+
+    const uint8_t hotpixelMode = ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF;
+    UPDATE(md, ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE, &hotpixelMode, 1);
+
+    bool support30Fps = false;
+    int32_t maxFps = std::numeric_limits<int32_t>::min();
+    for (const auto& supportedFormat : mSupportedFormats) {
+        for (const auto& frameRate : supportedFormat.frameRates) {
+            int32_t framerateInt = static_cast<int32_t>(frameRate);
+            if (maxFps < framerateInt) {
+                maxFps = framerateInt;
+            }
+            if (framerateInt == 30) {
+                support30Fps = true;
+                break;
+            }
+        }
+        if (support30Fps) {
+            break;
+        }
+    }
+    int32_t defaultFramerate = support30Fps ? 30 : maxFps;
+    int32_t defaultFpsRange[] = {defaultFramerate, defaultFramerate};
+    UPDATE(md, ANDROID_CONTROL_AE_TARGET_FPS_RANGE, defaultFpsRange, ARRAY_SIZE(defaultFpsRange));
+
+    uint8_t antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
+    UPDATE(md, ANDROID_CONTROL_AE_ANTIBANDING_MODE, &antibandingMode, 1);
+
+    const uint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;
+    UPDATE(md, ANDROID_CONTROL_MODE, &controlMode, 1);
+
+    auto requestTemplates = hidl_enum_iterator<RequestTemplate>();
+    for (RequestTemplate type : requestTemplates) {
+        ::android::hardware::camera::common::V1_0::helper::CameraMetadata mdCopy = md;
+        uint8_t intent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+        switch (type) {
+            case RequestTemplate::PREVIEW:
+                intent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
+                break;
+            case RequestTemplate::STILL_CAPTURE:
+                intent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
+                break;
+            case RequestTemplate::VIDEO_RECORD:
+                intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
+                break;
+            case RequestTemplate::VIDEO_SNAPSHOT:
+                intent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;
+                break;
+            default:
+                ALOGV("%s: unsupported RequestTemplate type %d", __FUNCTION__, type);
+                continue;
+        }
+        UPDATE(mdCopy, ANDROID_CONTROL_CAPTURE_INTENT, &intent, 1);
+
+        camera_metadata_t* rawMd = mdCopy.release();
+        CameraMetadata hidlMd;
+        hidlMd.setToExternal(
+                (uint8_t*) rawMd, get_camera_metadata_size(rawMd));
+        mDefaultRequests[type] = hidlMd;
+        free_camera_metadata(rawMd);
+    }
+
+    return OK;
+}
+
+status_t ExternalCameraDeviceSession::fillCaptureResult(
+        common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
+    // android.control
+    // For USB camera, we don't know the AE state. Set the state to converged to
+    // indicate the frame should be good to use. Then apps don't have to wait the
+    // AE state.
+    const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
+    UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
+
+    const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+    UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
+
+    bool afTrigger = mAfTrigger;
+    if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+        Mutex::Autolock _l(mLock);
+        camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+        if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+            mAfTrigger = afTrigger = true;
+        } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+            mAfTrigger = afTrigger = false;
+        }
+    }
+
+    // For USB camera, the USB camera handles everything and we don't have control
+    // over AF. We only simply fake the AF metadata based on the request
+    // received here.
+    uint8_t afState;
+    if (afTrigger) {
+        afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+    } else {
+        afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+    }
+    UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+    // Set AWB state to converged to indicate the frame should be good to use.
+    const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
+    UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+
+    const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+    UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
+
+    camera_metadata_ro_entry active_array_size =
+        mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+    if (active_array_size.count == 0) {
+        ALOGE("%s: cannot find active array size!", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+    UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
+    // android.scaler
+    const int32_t crop_region[] = {
+          active_array_size.data.i32[0], active_array_size.data.i32[1],
+          active_array_size.data.i32[2], active_array_size.data.i32[3],
+    };
+    UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
+
+    // android.sensor
+    UPDATE(md, ANDROID_SENSOR_TIMESTAMP, &timestamp, 1);
+
+    // android.statistics
+    const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+    UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
+
+    const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
+    UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
+
+    return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
new file mode 100644
index 0000000..212573a
--- /dev/null
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "ExtCamUtils@3.4"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include <cmath>
+#include <sys/mman.h>
+#include <linux/videodev2.h>
+#include "ExternalCameraUtils.h"
+#include "tinyxml2.h" // XML parsing
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+namespace {
+    const int  kDefaultJpegBufSize = 5 << 20; // 5MB
+    const int  kDefaultNumVideoBuffer = 4;
+    const int  kDefaultNumStillBuffer = 2;
+} // anonymous namespace
+
+const char* ExternalCameraDeviceConfig::kDefaultCfgPath = "/vendor/etc/external_camera_config.xml";
+
+V4L2Frame::V4L2Frame(
+        uint32_t w, uint32_t h, uint32_t fourcc,
+        int bufIdx, int fd, uint32_t dataSize, uint64_t offset) :
+        mWidth(w), mHeight(h), mFourcc(fourcc),
+        mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {}
+
+int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
+    if (data == nullptr || dataSize == nullptr) {
+        ALOGI("%s: V4L2 buffer map bad argument: data %p, dataSize %p",
+                __FUNCTION__, data, dataSize);
+        return -EINVAL;
+    }
+
+    std::lock_guard<std::mutex> lk(mLock);
+    if (!mMapped) {
+        void* addr = mmap(NULL, mDataSize, PROT_READ, MAP_SHARED, mFd, mOffset);
+        if (addr == MAP_FAILED) {
+            ALOGE("%s: V4L2 buffer map failed: %s", __FUNCTION__, strerror(errno));
+            return -EINVAL;
+        }
+        mData = static_cast<uint8_t*>(addr);
+        mMapped = true;
+    }
+    *data = mData;
+    *dataSize = mDataSize;
+    ALOGV("%s: V4L map FD %d, data %p size %zu", __FUNCTION__, mFd, mData, mDataSize);
+    return 0;
+}
+
+int V4L2Frame::unmap() {
+    std::lock_guard<std::mutex> lk(mLock);
+    if (mMapped) {
+        ALOGV("%s: V4L unmap data %p size %zu", __FUNCTION__, mData, mDataSize);
+        if (munmap(mData, mDataSize) != 0) {
+            ALOGE("%s: V4L2 buffer unmap failed: %s", __FUNCTION__, strerror(errno));
+            return -EINVAL;
+        }
+        mMapped = false;
+    }
+    return 0;
+}
+
+V4L2Frame::~V4L2Frame() {
+    unmap();
+}
+
+AllocatedFrame::AllocatedFrame(
+        uint32_t w, uint32_t h) :
+        mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {};
+
+AllocatedFrame::~AllocatedFrame() {}
+
+int AllocatedFrame::allocate(YCbCrLayout* out) {
+    std::lock_guard<std::mutex> lk(mLock);
+    if ((mWidth % 2) || (mHeight % 2)) {
+        ALOGE("%s: bad dimension %dx%d (not multiple of 2)", __FUNCTION__, mWidth, mHeight);
+        return -EINVAL;
+    }
+
+    uint32_t dataSize = mWidth * mHeight * 3 / 2; // YUV420
+    if (mData.size() != dataSize) {
+        mData.resize(dataSize);
+    }
+
+    if (out != nullptr) {
+        out->y = mData.data();
+        out->yStride = mWidth;
+        uint8_t* cbStart = mData.data() + mWidth * mHeight;
+        uint8_t* crStart = cbStart + mWidth * mHeight / 4;
+        out->cb = cbStart;
+        out->cr = crStart;
+        out->cStride = mWidth / 2;
+        out->chromaStep = 1;
+    }
+    return 0;
+}
+
+int AllocatedFrame::getLayout(YCbCrLayout* out) {
+    IMapper::Rect noCrop = {0, 0,
+            static_cast<int32_t>(mWidth),
+            static_cast<int32_t>(mHeight)};
+    return getCroppedLayout(noCrop, out);
+}
+
+int AllocatedFrame::getCroppedLayout(const IMapper::Rect& rect, YCbCrLayout* out) {
+    if (out == nullptr) {
+        ALOGE("%s: null out", __FUNCTION__);
+        return -1;
+    }
+
+    std::lock_guard<std::mutex> lk(mLock);
+    if ((rect.left + rect.width) > static_cast<int>(mWidth) ||
+        (rect.top + rect.height) > static_cast<int>(mHeight) ||
+            (rect.left % 2) || (rect.top % 2) || (rect.width % 2) || (rect.height % 2)) {
+        ALOGE("%s: bad rect left %d top %d w %d h %d", __FUNCTION__,
+                rect.left, rect.top, rect.width, rect.height);
+        return -1;
+    }
+
+    out->y = mData.data() + mWidth * rect.top + rect.left;
+    out->yStride = mWidth;
+    uint8_t* cbStart = mData.data() + mWidth * mHeight;
+    uint8_t* crStart = cbStart + mWidth * mHeight / 4;
+    out->cb = cbStart + mWidth * rect.top / 4 + rect.left / 2;
+    out->cr = crStart + mWidth * rect.top / 4 + rect.left / 2;
+    out->cStride = mWidth / 2;
+    out->chromaStep = 1;
+    return 0;
+}
+
+
+ExternalCameraDeviceConfig ExternalCameraDeviceConfig::loadFromCfg(const char* cfgPath) {
+    using namespace tinyxml2;
+    ExternalCameraDeviceConfig ret;
+
+    XMLDocument configXml;
+    XMLError err = configXml.LoadFile(cfgPath);
+    if (err != XML_SUCCESS) {
+        ALOGE("%s: Unable to load external camera config file '%s'. Error: %s",
+                __FUNCTION__, cfgPath, XMLDocument::ErrorIDToName(err));
+        return ret;
+    } else {
+        ALOGI("%s: load external camera config succeed!", __FUNCTION__);
+    }
+
+    XMLElement *extCam = configXml.FirstChildElement("ExternalCamera");
+    if (extCam == nullptr) {
+        ALOGI("%s: no external camera config specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement *deviceCfg = extCam->FirstChildElement("Device");
+    if (deviceCfg == nullptr) {
+        ALOGI("%s: no external camera device config specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement *jpegBufSz = deviceCfg->FirstChildElement("MaxJpegBufferSize");
+    if (jpegBufSz == nullptr) {
+        ALOGI("%s: no max jpeg buffer size specified", __FUNCTION__);
+    } else {
+        ret.maxJpegBufSize = jpegBufSz->UnsignedAttribute("bytes", /*Default*/kDefaultJpegBufSize);
+    }
+
+    XMLElement *numVideoBuf = deviceCfg->FirstChildElement("NumVideoBuffers");
+    if (numVideoBuf == nullptr) {
+        ALOGI("%s: no num video buffers specified", __FUNCTION__);
+    } else {
+        ret.numVideoBuffers =
+                numVideoBuf->UnsignedAttribute("count", /*Default*/kDefaultNumVideoBuffer);
+    }
+
+    XMLElement *numStillBuf = deviceCfg->FirstChildElement("NumStillBuffers");
+    if (numStillBuf == nullptr) {
+        ALOGI("%s: no num still buffers specified", __FUNCTION__);
+    } else {
+        ret.numStillBuffers =
+                numStillBuf->UnsignedAttribute("count", /*Default*/kDefaultNumStillBuffer);
+    }
+
+    XMLElement *fpsList = deviceCfg->FirstChildElement("FpsList");
+    if (fpsList == nullptr) {
+        ALOGI("%s: no fps list specified", __FUNCTION__);
+    } else {
+        std::vector<FpsLimitation> limits;
+        XMLElement *row = fpsList->FirstChildElement("Limit");
+        while (row != nullptr) {
+            FpsLimitation prevLimit {{0, 0}, 1000.0};
+            FpsLimitation limit;
+            limit.size = {
+                row->UnsignedAttribute("width", /*Default*/0),
+                row->UnsignedAttribute("height", /*Default*/0)};
+            limit.fpsUpperBound = row->FloatAttribute("fpsBound", /*Default*/1000.0);
+            if (limit.size.width <= prevLimit.size.width ||
+                    limit.size.height <= prevLimit.size.height ||
+                    limit.fpsUpperBound >= prevLimit.fpsUpperBound) {
+                ALOGE("%s: FPS limit list must have increasing size and decreasing fps!"
+                        " Prev %dx%d@%f, Current %dx%d@%f", __FUNCTION__,
+                        prevLimit.size.width, prevLimit.size.height, prevLimit.fpsUpperBound,
+                        limit.size.width, limit.size.height, limit.fpsUpperBound);
+                return ret;
+            }
+            limits.push_back(limit);
+            row = row->NextSiblingElement("Limit");
+        }
+        ret.fpsLimits = limits;
+    }
+
+    ALOGI("%s: external camera cfd loaded: maxJpgBufSize %d,"
+            " num video buffers %d, num still buffers %d",
+            __FUNCTION__, ret.maxJpegBufSize,
+            ret.numVideoBuffers, ret.numStillBuffers);
+    for (const auto& limit : ret.fpsLimits) {
+        ALOGI("%s: fpsLimitList: %dx%d@%f", __FUNCTION__,
+                limit.size.width, limit.size.height, limit.fpsUpperBound);
+    }
+    return ret;
+}
+
+ExternalCameraDeviceConfig::ExternalCameraDeviceConfig() :
+        maxJpegBufSize(kDefaultJpegBufSize),
+        numVideoBuffers(kDefaultNumVideoBuffer),
+        numStillBuffers(kDefaultNumStillBuffer) {
+    fpsLimits.push_back({/*Size*/{ 640,  480}, /*FPS upper bound*/30.0});
+    fpsLimits.push_back({/*Size*/{1280,  720}, /*FPS upper bound*/15.0});
+    fpsLimits.push_back({/*Size*/{1920, 1080}, /*FPS upper bound*/10.0});
+    fpsLimits.push_back({/*Size*/{4096, 3072}, /*FPS upper bound*/5.0});
+}
+
+bool isAspectRatioClose(float ar1, float ar2) {
+    const float kAspectRatioMatchThres = 0.025f; // This threshold is good enough to distinguish
+                                                // 4:3/16:9/20:9
+                                                // 1.33 / 1.78 / 2
+    return (std::abs(ar1 - ar2) < kAspectRatioMatchThres);
+}
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.4/default/OWNERS b/camera/device/3.4/default/OWNERS
new file mode 100644
index 0000000..18acfee
--- /dev/null
+++ b/camera/device/3.4/default/OWNERS
@@ -0,0 +1,6 @@
+cychen@google.com
+epeev@google.com
+etalvala@google.com
+shuzhenwang@google.com
+yinchiayeh@google.com
+zhijunhe@google.com
diff --git a/camera/device/3.4/default/convert.cpp b/camera/device/3.4/default/convert.cpp
new file mode 100644
index 0000000..f12230c
--- /dev/null
+++ b/camera/device/3.4/default/convert.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.camera.device@3.4-convert-impl"
+#include <log/log.h>
+
+#include <cstring>
+#include "include/convert.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+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::BufferUsageFlags;
+
+void convertToHidl(const Camera3Stream* src, HalStream* dst) {
+    V3_3::implementation::convertToHidl(src, &dst->v3_3);
+    dst->physicalCameraId = src->physical_camera_id;
+}
+
+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(const Stream &src, Camera3Stream* dst) {
+    V3_2::implementation::convertFromHidl(src.v3_2, dst);
+    // Initialize physical_camera_id
+    dst->physical_camera_id = nullptr;
+    return;
+}
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.4/default/include/convert.h b/camera/device/3.4/default/include/convert.h
new file mode 100644
index 0000000..e8e3951
--- /dev/null
+++ b/camera/device/3.4/default/include/convert.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_V3_4_DEFAULT_INCLUDE_CONVERT_H_
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_V3_4_DEFAULT_INCLUDE_CONVERT_H_
+
+#include <android/hardware/camera/device/3.4/types.h>
+#include "hardware/camera3.h"
+#include "../../3.3/default/include/convert.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::implementation::Camera3Stream;
+
+void convertToHidl(const Camera3Stream* src, HalStream* dst);
+
+void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst);
+
+void convertFromHidl(const Stream &src, Camera3Stream* dst);
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_CAMERA_DEVICE_V3_4_DEFAULT_INCLUDE_CONVERT_H_
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
new file mode 100644
index 0000000..9cd7da7
--- /dev/null
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDeviceSession.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2017-2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE3SESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE3SESSION_H
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
+#include <../../3.3/default/CameraDeviceSession.h>
+#include <../../3.3/default/include/convert.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <deque>
+#include <map>
+#include <unordered_map>
+#include "CameraMetadata.h"
+#include "HandleImporter.h"
+#include "hardware/camera3.h"
+#include "hardware/camera_common.h"
+#include "utils/Mutex.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_4::StreamConfiguration;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_4::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_4::ICameraDeviceCallback;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+struct CameraDeviceSession : public V3_3::implementation::CameraDeviceSession {
+
+    CameraDeviceSession(camera3_device_t*,
+            const camera_metadata_t* deviceInfo,
+            const sp<V3_2::ICameraDeviceCallback>&);
+    virtual ~CameraDeviceSession();
+
+    virtual sp<V3_2::ICameraDeviceSession> getInterface() override {
+        return new TrampolineSessionInterface_3_4(this);
+    }
+
+protected:
+    // Methods from v3.3 and earlier will trampoline to inherited implementation
+
+    // New methods for v3.4
+    Return<void> constructDefaultRequestSettings_3_4(
+            RequestTemplate type,
+            ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb);
+
+    Return<void> configureStreams_3_4(
+            const StreamConfiguration& requestedConfiguration,
+            ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb);
+
+    bool preProcessConfigurationLocked_3_4(
+            const StreamConfiguration& requestedConfiguration,
+            camera3_stream_configuration_t *stream_list /*out*/,
+            hidl_vec<camera3_stream_t*> *streams /*out*/);
+    void postProcessConfigurationLocked_3_4(const StreamConfiguration& requestedConfiguration);
+
+    Return<void> processCaptureRequest_3_4(
+            const hidl_vec<V3_4::CaptureRequest>& requests,
+            const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+            ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb);
+    Status processOneCaptureRequest_3_4(const V3_4::CaptureRequest& request);
+
+    std::map<int, std::string> mPhysicalCameraIdMap;
+
+    static V3_2::implementation::callbacks_process_capture_result_t sProcessCaptureResult_3_4;
+    static V3_2::implementation::callbacks_notify_t sNotify_3_4;
+
+    class ResultBatcher_3_4 : public V3_3::implementation::CameraDeviceSession::ResultBatcher {
+    public:
+        ResultBatcher_3_4(const sp<V3_2::ICameraDeviceCallback>& callback);
+        void processCaptureResult_3_4(CaptureResult& result);
+    private:
+        void freeReleaseFences_3_4(hidl_vec<CaptureResult>&);
+        void processOneCaptureResult_3_4(CaptureResult& result);
+        void invokeProcessCaptureResultCallback_3_4(hidl_vec<CaptureResult> &results,
+                bool tryWriteFmq);
+
+        sp<ICameraDeviceCallback> mCallback_3_4;
+    } mResultBatcher_3_4;
+
+    // Whether this camera device session is created with version 3.4 callback.
+    bool mHasCallback_3_4;
+private:
+
+    struct TrampolineSessionInterface_3_4 : public ICameraDeviceSession {
+        TrampolineSessionInterface_3_4(sp<CameraDeviceSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> constructDefaultRequestSettings(
+                V3_2::RequestTemplate type,
+                V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+            return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+            return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
+            return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+            return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> getCaptureRequestMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<Status> flush() override {
+            return mParent->flush();
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+        virtual Return<void> constructDefaultRequestSettings_3_4(
+                RequestTemplate type,
+                ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+            return mParent->constructDefaultRequestSettings_3_4(type, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_3(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_3_cb _hidl_cb) override {
+            return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_4(
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_4_cb _hidl_cb) override {
+            return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+        }
+
+    private:
+        sp<CameraDeviceSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE3SESSION_H
diff --git a/camera/device/3.4/default/include/device_v3_4_impl/CameraDevice_3_4.h b/camera/device/3.4/default/include/device_v3_4_impl/CameraDevice_3_4.h
new file mode 100644
index 0000000..95ee20e
--- /dev/null
+++ b/camera/device/3.4/default/include/device_v3_4_impl/CameraDevice_3_4.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE_H
+
+#include "utils/Mutex.h"
+#include "CameraModule.h"
+#include "CameraMetadata.h"
+#include "CameraDeviceSession.h"
+#include <../../3.2/default/CameraDevice_3_2.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_4 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+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;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct CameraDevice : public V3_2::implementation::CameraDevice {
+
+    // 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 objects in order to notify CameraDevice when the underlying
+    // camera is detached.
+    // Delegates nearly all work to CameraDevice_3_2
+    CameraDevice(sp<CameraModule> module,
+                 const std::string& cameraId,
+                 const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames);
+    ~CameraDevice();
+
+protected:
+    virtual sp<V3_2::implementation::CameraDeviceSession> createSession(camera3_device_t*,
+            const camera_metadata_t* deviceInfo,
+            const sp<V3_2::ICameraDeviceCallback>&) override;
+
+};
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_CAMERADEVICE_H
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
new file mode 100644
index 0000000..fabf26a
--- /dev/null
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <include/convert.h>
+#include <chrono>
+#include <condition_variable>
+#include <list>
+#include <unordered_map>
+#include <unordered_set>
+#include "CameraMetadata.h"
+#include "HandleImporter.h"
+#include "Exif.h"
+#include "utils/KeyedVector.h"
+#include "utils/Mutex.h"
+#include "utils/Thread.h"
+#include "android-base/unique_fd.h"
+#include "ExternalCameraUtils.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_4::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_4::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_2::DataspaceFlags;
+using ::android::hardware::camera::device::V3_2::CameraBlob;
+using ::android::hardware::camera::device::V3_2::CameraBlobId;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_4::ICameraDeviceSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+struct ExternalCameraDeviceSession : public virtual RefBase {
+
+    ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
+            const ExternalCameraDeviceConfig& cfg,
+            const std::vector<SupportedV4L2Format>& sortedFormats,
+            const CroppingType& croppingType,
+            const common::V1_0::helper::CameraMetadata& chars,
+            unique_fd v4l2Fd);
+    virtual ~ExternalCameraDeviceSession();
+    // Call by CameraDevice to dump active device states
+    void dumpState(const native_handle_t*);
+    // Caller must use this method to check if CameraDeviceSession ctor failed
+    bool isInitFailed() { return mInitFail; }
+    bool isClosed();
+
+    // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+    // dealing with minor version revs and simultaneous implementation and interface inheritance
+    virtual sp<ICameraDeviceSession> getInterface() {
+        return new TrampolineSessionInterface_3_4(this);
+    }
+
+    static const int kMaxProcessedStream = 2;
+    static const int kMaxStallStream = 1;
+
+protected:
+
+    // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow
+
+    Return<void> constructDefaultRequestSettings(
+            V3_2::RequestTemplate,
+            ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb);
+
+    Return<void> constructDefaultRequestSettings_3_4(
+            RequestTemplate type,
+            ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb);
+
+    Return<void> configureStreams(
+            const V3_2::StreamConfiguration&,
+            ICameraDeviceSession::configureStreams_cb);
+
+    Return<void> getCaptureRequestMetadataQueue(
+        ICameraDeviceSession::getCaptureRequestMetadataQueue_cb);
+
+    Return<void> getCaptureResultMetadataQueue(
+        ICameraDeviceSession::getCaptureResultMetadataQueue_cb);
+
+    Return<void> processCaptureRequest(
+            const hidl_vec<CaptureRequest>&,
+            const hidl_vec<BufferCache>&,
+            ICameraDeviceSession::processCaptureRequest_cb);
+
+    Return<Status> flush();
+    Return<void> close();
+
+    Return<void> configureStreams_3_3(
+            const V3_2::StreamConfiguration&,
+            ICameraDeviceSession::configureStreams_3_3_cb);
+
+    Return<void> configureStreams_3_4(
+            const V3_4::StreamConfiguration& requestedConfiguration,
+            ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb);
+
+    Return<void> processCaptureRequest_3_4(
+            const hidl_vec<V3_4::CaptureRequest>& requests,
+            const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+            ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb);
+
+protected:
+    struct HalStreamBuffer {
+        int32_t streamId;
+        uint64_t bufferId;
+        uint32_t width;
+        uint32_t height;
+        PixelFormat format;
+        V3_2::BufferUsageFlags usage;
+        buffer_handle_t* bufPtr;
+        int acquireFence;
+        bool fenceTimeout;
+    };
+
+    struct HalRequest {
+        uint32_t frameNumber;
+        common::V1_0::helper::CameraMetadata setting;
+        sp<V4L2Frame> frameIn;
+        nsecs_t shutterTs;
+        std::vector<HalStreamBuffer> buffers;
+    };
+
+    Status constructDefaultRequestSettingsRaw(RequestTemplate type,
+            V3_2::CameraMetadata *outMetadata);
+
+    bool initialize();
+    Status initStatus() const;
+    status_t initDefaultRequests();
+    status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
+    Status configureStreams(const V3_2::StreamConfiguration&, V3_3::HalStreamConfiguration* out);
+    int configureV4l2StreamLocked(const SupportedV4L2Format& fmt);
+    int v4l2StreamOffLocked();
+
+    // TODO: change to unique_ptr for better tracking
+    sp<V4L2Frame> dequeueV4l2FrameLocked(); // Called with mLock hold
+    void enqueueV4l2Frame(const sp<V4L2Frame>&);
+
+    // Check if input Stream is one of supported stream setting on this device
+    bool isSupported(const Stream&);
+
+    // Validate and import request's output buffers and acquire fence
+    Status importRequest(
+            const CaptureRequest& request,
+            hidl_vec<buffer_handle_t*>& allBufPtrs,
+            hidl_vec<int>& allFences);
+    static void cleanupInflightFences(
+            hidl_vec<int>& allFences, size_t numFences);
+    void cleanupBuffersLocked(int id);
+    void updateBufferCaches(const hidl_vec<BufferCache>& cachesToRemove);
+
+    Status processOneCaptureRequest(const CaptureRequest& request);
+
+    Status processCaptureResult(HalRequest&);
+    Status processCaptureRequestError(HalRequest&);
+    void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs);
+    void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec);
+    void invokeProcessCaptureResultCallback(
+            hidl_vec<CaptureResult> &results, bool tryWriteFmq);
+    static void freeReleaseFences(hidl_vec<CaptureResult>&);
+
+    Size getMaxJpegResolution() const;
+    Size getMaxThumbResolution() const;
+
+    ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
+
+    class OutputThread : public android::Thread {
+    public:
+        OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
+        ~OutputThread();
+
+        Status allocateIntermediateBuffers(
+                const Size& v4lSize, const Size& thumbSize,
+                const hidl_vec<Stream>& streams);
+        Status submitRequest(const HalRequest&);
+        void flush();
+        virtual bool threadLoop() override;
+
+    private:
+        static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
+                static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
+                static_cast<uint32_t>('X') << 24;
+        // returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
+        static uint32_t getFourCcFromLayout(const YCbCrLayout&);
+        static int getCropRect(
+                CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
+
+        static const int kReqWaitTimeoutSec = 3;
+
+        void waitForNextRequest(HalRequest* out);
+        int cropAndScaleLocked(
+                sp<AllocatedFrame>& in, const Size& outSize,
+                YCbCrLayout* out);
+
+        int cropAndScaleThumbLocked(
+                sp<AllocatedFrame>& in, const Size& outSize,
+                YCbCrLayout* out);
+
+        int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out,
+                Size sz, uint32_t format);
+
+        static int encodeJpegYU12(const Size &inSz,
+                const YCbCrLayout& inLayout, int jpegQuality,
+                const void *app1Buffer, size_t app1Size,
+                void *out, size_t maxOutSize,
+                size_t &actualCodeSize);
+
+        int createJpegLocked(HalStreamBuffer &halBuf, HalRequest &req);
+
+        mutable std::mutex mLock;
+        std::condition_variable mRequestCond;
+        wp<ExternalCameraDeviceSession> mParent;
+        CroppingType mCroppingType;
+        std::list<HalRequest> mRequestList;
+        // V4L2 frameIn
+        // (MJPG decode)-> mYu12Frame
+        // (Scale)-> mScaledYu12Frames
+        // (Format convert) -> output gralloc frames
+        sp<AllocatedFrame> mYu12Frame;
+        sp<AllocatedFrame> mYu12ThumbFrame;
+        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
+        std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
+        YCbCrLayout mYu12FrameLayout;
+        YCbCrLayout mYu12ThumbFrameLayout;
+    };
+
+    // Protect (most of) HIDL interface methods from synchronized-entering
+    mutable Mutex mInterfaceLock;
+
+    mutable Mutex mLock; // Protect all private members except otherwise noted
+    const sp<ICameraDeviceCallback> mCallback;
+    const ExternalCameraDeviceConfig mCfg;
+    const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+    const std::vector<SupportedV4L2Format> mSupportedFormats;
+    const CroppingType mCroppingType;
+    unique_fd mV4l2Fd;
+    // device is closed either
+    //    - closed by user
+    //    - init failed
+    //    - camera disconnected
+    bool mClosed = false;
+    bool mInitFail = false;
+    bool mFirstRequest = false;
+    common::V1_0::helper::CameraMetadata mLatestReqSetting;
+
+    bool mV4l2Streaming = false;
+    SupportedV4L2Format mV4l2StreamingFmt;
+    size_t mV4L2BufferCount;
+
+    static const int kBufferWaitTimeoutSec = 3; // TODO: handle long exposure (or not allowing)
+    std::mutex mV4l2BufferLock; // protect the buffer count and condition below
+    std::condition_variable mV4L2BufferReturned;
+    size_t mNumDequeuedV4l2Buffers = 0;
+
+    sp<OutputThread> mOutputThread;
+
+    // Stream ID -> Camera3Stream cache
+    std::unordered_map<int, Stream> mStreamMap;
+    std::unordered_set<uint32_t>  mInflightFrames;
+
+    // buffers currently circulating between HAL and camera service
+    // key: bufferId sent via HIDL interface
+    // value: imported buffer_handle_t
+    // Buffer will be imported during processCaptureRequest and will be freed
+    // when the its stream is deleted or camera device session is closed
+    typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
+    // Stream ID -> circulating buffers map
+    std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+    bool mAfTrigger = false;
+
+    static HandleImporter sHandleImporter;
+
+    /* Beginning of members not changed after initialize() */
+    using RequestMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+    std::unique_ptr<RequestMetadataQueue> mRequestMetadataQueue;
+    using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+    std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+    // Protect against invokeProcessCaptureResultCallback()
+    Mutex mProcessCaptureResultLock;
+
+    std::unordered_map<RequestTemplate, CameraMetadata> mDefaultRequests;
+
+    const Size mMaxThumbResolution;
+    const Size mMaxJpegResolution;
+    /* End of members not changed after initialize() */
+
+private:
+
+    struct TrampolineSessionInterface_3_4 : public ICameraDeviceSession {
+        TrampolineSessionInterface_3_4(sp<ExternalCameraDeviceSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> constructDefaultRequestSettings(
+                V3_2::RequestTemplate type,
+                V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+            return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+            return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+            return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> getCaptureRequestMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<Status> flush() override {
+            return mParent->flush();
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+        virtual Return<void> constructDefaultRequestSettings_3_4(
+                RequestTemplate type,
+                ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+            return mParent->constructDefaultRequestSettings_3_4(type, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_3(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_3_cb _hidl_cb) override {
+            return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_4(
+                const V3_4::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_4_cb _hidl_cb) override {
+            return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest_3_4(const hidl_vec<V3_4::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
+            return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
+        }
+
+    private:
+        sp<ExternalCameraDeviceSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
new file mode 100644
index 0000000..ef4b41c
--- /dev/null
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE_H
+
+#include "utils/Mutex.h"
+#include "CameraMetadata.h"
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+#include "ExternalCameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_2::ICameraDevice;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+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;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct ExternalCameraDevice : public ICameraDevice {
+
+    // Called by external camera 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 objects in order to notify CameraDevice when the underlying
+    // camera is detached.
+    ExternalCameraDevice(const std::string& cameraId);
+    ~ExternalCameraDevice();
+
+    // Caller must use this method to check if CameraDevice ctor failed
+    bool isInitFailed();
+
+    /* 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) override;
+
+    // Open the device HAL and also return a default capture session
+    Return<void> open(const sp<ICameraDeviceCallback>&, open_cb) override;
+
+    // Forward the dump call to the opened session, or do nothing
+    Return<void> dumpState(const ::android::hardware::hidl_handle&) override;
+    /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */
+
+protected:
+    void getFrameRateList(int fd, float fpsUpperBound, SupportedV4L2Format* format);
+    // Init supported w/h/format/fps in mSupportedFormats. Caller still owns fd
+    void initSupportedFormatsLocked(int fd);
+
+    status_t initCameraCharacteristics();
+    // Init non-device dependent keys
+    status_t initDefaultCharsKeys(::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+    // Init camera control chars keys. Caller still owns fd
+    status_t initCameraControlsCharsKeys(int fd,
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+    // Init camera output configuration related keys.  Caller still owns fd
+    status_t initOutputCharsKeys(int fd,
+            ::android::hardware::camera::common::V1_0::helper::CameraMetadata*);
+
+    static CroppingType initCroppingType(/*inout*/std::vector<SupportedV4L2Format>*);
+
+    Mutex mLock;
+    bool mInitFailed = false;
+    std::string mCameraId;
+    const ExternalCameraDeviceConfig mCfg;
+    std::vector<SupportedV4L2Format> mSupportedFormats;
+    CroppingType mCroppingType;
+
+    wp<ExternalCameraDeviceSession> mSession = nullptr;
+
+    ::android::hardware::camera::common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+};
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE_H
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
new file mode 100644
index 0000000..849f947
--- /dev/null
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
+
+#include <inttypes.h>
+#include "utils/LightRefBase.h"
+#include <mutex>
+#include <vector>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+
+using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_4 {
+namespace implementation {
+
+struct SupportedV4L2Format {
+    uint32_t width;
+    uint32_t height;
+    uint32_t fourcc;
+    // All supported frame rate for this w/h/fourcc combination
+    std::vector<float> frameRates;
+};
+
+// A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
+// Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
+class V4L2Frame : public virtual VirtualLightRefBase {
+public:
+    V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd,
+              uint32_t dataSize, uint64_t offset);
+    ~V4L2Frame() override;
+    const uint32_t mWidth;
+    const uint32_t mHeight;
+    const uint32_t mFourcc;
+    const int mBufferIndex; // for later enqueue
+    int map(uint8_t** data, size_t* dataSize);
+    int unmap();
+private:
+    std::mutex mLock;
+    const int mFd; // used for mmap but doesn't claim ownership
+    const size_t mDataSize;
+    const uint64_t mOffset; // used for mmap
+    uint8_t* mData = nullptr;
+    bool  mMapped = false;
+};
+
+// A RAII class representing a CPU allocated YUV frame used as intermeidate buffers
+// when generating output images.
+class AllocatedFrame : public virtual VirtualLightRefBase {
+public:
+    AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size?
+    ~AllocatedFrame() override;
+    const uint32_t mWidth;
+    const uint32_t mHeight;
+    const uint32_t mFourcc; // Only support YU12 format for now
+    int allocate(YCbCrLayout* out = nullptr);
+    int getLayout(YCbCrLayout* out);
+    int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
+private:
+    std::mutex mLock;
+    std::vector<uint8_t> mData;
+};
+
+enum CroppingType {
+    HORIZONTAL = 0,
+    VERTICAL = 1
+};
+
+struct Size {
+    uint32_t width;
+    uint32_t height;
+
+    bool operator==(const Size& other) const {
+        return (width == other.width && height == other.height);
+    }
+};
+
+struct SizeHasher {
+    size_t operator()(const Size& sz) const {
+        size_t result = 1;
+        result = 31 * result + sz.width;
+        result = 31 * result + sz.height;
+        return result;
+    }
+};
+
+struct ExternalCameraDeviceConfig {
+    static const char* kDefaultCfgPath;
+    static ExternalCameraDeviceConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
+
+    // Maximal size of a JPEG buffer, in bytes
+    uint32_t maxJpegBufSize;
+
+    // Maximum Size that can sustain 30fps streaming
+    Size maxVideoSize;
+
+    // Size of v4l2 buffer queue when streaming <= kMaxVideoSize
+    uint32_t numVideoBuffers;
+
+    // Size of v4l2 buffer queue when streaming > kMaxVideoSize
+    uint32_t numStillBuffers;
+
+    struct FpsLimitation {
+        Size size;
+        float fpsUpperBound;
+    };
+    std::vector<FpsLimitation> fpsLimits;
+
+private:
+    ExternalCameraDeviceConfig();
+};
+
+// Aspect ratio is defined as width/height here and ExternalCameraDevice
+// will guarantee all supported sizes has width >= height (so aspect ratio >= 1.0)
+#define ASPECT_RATIO(sz) (static_cast<float>((sz).width) / (sz).height)
+const float kMaxAspectRatio = std::numeric_limits<float>::max();
+const float kMinAspectRatio = 1.f;
+
+bool isAspectRatioClose(float ar1, float ar2);
+
+}  // namespace implementation
+}  // namespace V3_4
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
diff --git a/camera/device/3.4/types.hal b/camera/device/3.4/types.hal
new file mode 100644
index 0000000..c8ebb17
--- /dev/null
+++ b/camera/device/3.4/types.hal
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.4;
+
+import @3.2::RequestTemplate;
+import @3.2::StreamConfigurationMode;
+import @3.2::Stream;
+import @3.3::HalStream;
+import @3.2::CameraMetadata;
+import @3.2::CaptureRequest;
+import @3.2::CaptureResult;
+
+/**
+ * Stream:
+ *
+ * A descriptor for a single camera input or output stream. A stream is defined
+ * by the framework by its buffer resolution and format, and additionally by the
+ * HAL with the gralloc usage flags and the maximum in-flight buffer count.
+ *
+ * This version extends the @3.2 Stream with the physicalCameraId and bufferSize field.
+ */
+struct Stream {
+    /**
+     * The definition of Stream from the prior version
+     */
+    @3.2::Stream v3_2;
+
+    /**
+     * The physical camera id this stream belongs to.
+     *
+     * If the camera device is not a logical multi camera, or if the camera is a logical
+     * multi camera but the stream is not a physical output stream, this field will point to a
+     * 0-length string.
+     *
+     * A logical multi camera is a camera device backed by multiple physical cameras that
+     * are also exposed to the application. And for a logical multi camera, a physical output
+     * stream is an output stream specifically requested on an underlying physical camera.
+     *
+     * A logical camera is a camera device backed by multiple physical camera
+     * devices. And a physical stream is a stream specifically requested on a
+     * underlying physical camera device.
+     *
+     * For an input stream, this field is guaranteed to be a 0-length string.
+     *
+     * When not empty, this field is the <id> field of one of the full-qualified device
+     * instance names returned by getCameraIdList().
+     */
+    string physicalCameraId;
+
+    /**
+     * The size of a buffer from this Stream, in bytes.
+     *
+     * For non PixelFormat::BLOB formats, this entry must be 0 and HAL should use
+     * android.hardware.graphics.mapper lockYCbCr API to get buffer layout.
+     *
+     * For BLOB format with dataSpace Dataspace::DEPTH, this must be zero and and HAL must
+     * determine the buffer size based on ANDROID_DEPTH_MAX_DEPTH_SAMPLES.
+     *
+     * For BLOB format with dataSpace Dataspace::JFIF, this must be non-zero and represent the
+     * maximal size HAL can lock using android.hardware.graphics.mapper lock API.
+     *
+     */
+    uint32_t bufferSize;
+};
+
+/**
+ * New request templates, extending the @3.2 RequestTemplate
+ */
+enum RequestTemplate : @3.2::RequestTemplate {
+    /**
+     * A template for selecting camera parameters that match TEMPLATE_PREVIEW as closely as
+     * possible while improving the camera output for motion tracking use cases.
+     *
+     * This template is best used by applications that are frequently switching between motion
+     * tracking use cases and regular still capture use cases, to minimize the IQ changes
+     * when swapping use cases.
+     *
+     * This template is guaranteed to be supported on camera devices that support the
+     * REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING capability.
+     */
+    MOTION_TRACKING_PREVIEW = 7,
+
+    /**
+     * A template for selecting camera parameters that maximize the quality of camera output for
+     * motion tracking use cases.
+     *
+     * This template is best used by applications dedicated to motion tracking applications,
+     * which aren't concerned about fast switches between motion tracking and other use cases.
+     *
+     * This template is guaranteed to be supported on camera devices that support the
+     * REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING capability.
+     */
+    MOTION_TRACKING_BEST = 8,
+};
+
+/**
+ * StreamConfiguration:
+ *
+ * Identical to @3.2::StreamConfiguration, except that it contains session
+ * parameters, and the streams vector contains @3.4::Stream.
+ */
+struct StreamConfiguration {
+    /**
+     * An array of camera stream pointers, defining the input/output
+     * configuration for the camera HAL device.
+     */
+    vec<Stream> streams;
+
+    /**
+     * The definition of operation mode from prior version.
+     *
+     */
+    StreamConfigurationMode operationMode;
+
+    /**
+     * Session wide camera parameters.
+     *
+     * The session parameters contain the initial values of any request keys that were
+     * made available via ANDROID_REQUEST_AVAILABLE_SESSION_KEYS. The Hal implementation
+     * can advertise any settings that can potentially introduce unexpected delays when
+     * their value changes during active process requests. Typical examples are
+     * parameters that trigger time-consuming HW re-configurations or internal camera
+     * pipeline updates. The field is optional, clients can choose to ignore it and avoid
+     * including any initial settings. If parameters are present, then hal must examine
+     * their values and configure the internal camera pipeline accordingly.
+     */
+    CameraMetadata sessionParams;
+};
+
+/**
+ * HalStream:
+ *
+ * The camera HAL's response to each requested stream configuration.
+ *
+ * This version extends the @3.3 HalStream with the physicalCameraId
+ * field
+ */
+struct HalStream {
+    /**
+     * The definition of HalStream from the prior version.
+     */
+    @3.3::HalStream v3_3;
+
+    /**
+     * The physical camera id the current Hal stream belongs to.
+     *
+     * If current camera device isn't a logical camera, or the Hal stream isn't
+     * from a physical camera of the logical camera, this must be an empty
+     * string.
+     *
+     * A logical camera is a camera device backed by multiple physical camera
+     * devices.
+     *
+     * When not empty, this field is the <id> field of one of the full-qualified device
+     * instance names returned by getCameraIdList().
+     */
+    string physicalCameraId;
+};
+
+/**
+ * HalStreamConfiguration:
+ *
+ * Identical to @3.3::HalStreamConfiguration, except that it contains @3.4::HalStream entries.
+ *
+ */
+struct HalStreamConfiguration {
+    vec<HalStream> streams;
+};
+
+/**
+ * PhysicalCameraSetting:
+ *
+ * Individual camera settings for logical camera backed by multiple physical devices.
+ * Clients are allowed to pass separate settings for each physical device that has
+ * corresponding configured HalStream and the respective stream id is present in the
+ * output buffers of the capture request.
+ */
+struct PhysicalCameraSetting {
+    /**
+     * If non-zero, read settings from request queue instead
+     * (see ICameraDeviceSession.getCaptureRequestMetadataQueue).
+     * If zero, read settings from .settings field.
+     */
+    uint64_t fmqSettingsSize;
+
+    /**
+     * Contains the physical device camera id. Any settings passed by client here
+     * should be applied for this physical device. In case the physical id is invalid or
+     * it is not present among the last configured streams, Hal should fail the process
+     * request and return Status::ILLEGAL_ARGUMENT.
+     */
+    string physicalCameraId;
+
+    /**
+     * If fmqSettingsSize is zero, the settings buffer contains the capture and
+     * processing parameters for the physical device with id 'phyCamId'.
+     * In case the individual settings are empty or missing, Hal should fail the
+     * request and return Status::ILLEGAL_ARGUMENT.
+     */
+    CameraMetadata settings;
+};
+
+/**
+ * CaptureRequest:
+ *
+ * A single request for image capture/buffer reprocessing, sent to the Camera
+ * HAL device by the framework in processCaptureRequest().
+ *
+ * The request contains the settings to be used for this capture, and the set of
+ * output buffers to write the resulting image data in. It may optionally
+ * contain an input buffer, in which case the request is for reprocessing that
+ * input buffer instead of capturing a new image with the camera sensor. The
+ * capture is identified by the frameNumber.
+ *
+ * In response, the camera HAL device must send a CaptureResult
+ * structure asynchronously to the framework, using the processCaptureResult()
+ * callback.
+ *
+ * Identical to @3.2::CaptureRequest, except that it contains @3.4::physCamSettings vector.
+ *
+ */
+struct CaptureRequest {
+    /**
+     * The definition of CaptureRequest from prior version.
+     */
+    @3.2::CaptureRequest v3_2;
+
+    /**
+     * A vector containing individual camera settings for logical camera backed by multiple physical
+     * devices. In case the vector is empty, Hal should use the settings field in 'v3_2'. The
+     * individual settings should only be honored for physical devices that have respective Hal
+     * stream. Physical devices that have a corresponding Hal stream but don't have attached
+     * settings here should use the settings field in 'v3_2'.
+     * If any of the physical settings in the array are applied on one or more devices, then the
+     * visual effect on any Hal streams attached to the logical camera is undefined.
+     */
+    vec<PhysicalCameraSetting> physicalCameraSettings;
+};
+
+/**
+ * PhysicalCameraMetadata:
+ *
+ * Individual camera metadata for a physical camera as part of a logical
+ * multi-camera. Camera HAL should return one such metadata for each physical
+ * camera being requested on.
+ */
+struct PhysicalCameraMetadata {
+    /**
+     * If non-zero, read metadata from result metadata queue instead
+     * (see ICameraDeviceSession.getCaptureResultMetadataQueue).
+     * If zero, read metadata from .metadata field.
+     */
+    uint64_t fmqMetadataSize;
+
+    /**
+     * Contains the physical device camera id. As long as the corresponding
+     * processCaptureRequest requests on a particular physical camera stream,
+     * the metadata for that physical camera should be generated for the capture
+     * result. */
+    string physicalCameraId;
+
+    /**
+     * If fmqMetadataSize is zero, the metadata buffer contains the metadata
+     * for the physical device with physicalCameraId.
+     *
+     * The v3_2 CaptureResult metadata is read first from the FMQ, followed by
+     * the physical cameras' metadata starting from index 0.
+     */
+    CameraMetadata metadata;
+};
+
+/**
+ * CaptureResult:
+ *
+ * Identical to @3.2::CaptureResult, except that it contains a list of
+ * physical camera metadata.
+ *
+ * Physical camera metadata needs to be generated if and only if a
+ * request is pending on a stream from that physical camera. For example,
+ * if the processCaptureRequest call doesn't request on physical camera
+ * streams, the physicalCameraMetadata field of the CaptureResult being returned
+ * should be an 0-size vector. If the processCaptureRequest call requests on
+ * streams from one of the physical camera, the physicalCameraMetadata field
+ * should contain one metadata describing the capture from that physical camera.
+ *
+ * For a CaptureResult that contains physical camera metadata, its
+ * partialResult field must be android.request.partialResultCount. In other
+ * words, the physicalCameraMetadata must only be contained in a final capture
+ * result.
+ */
+struct CaptureResult {
+    /**
+     * The definition of CaptureResult from the prior version.
+     */
+    @3.2::CaptureResult v3_2;
+
+    /**
+     * The physical metadata for logical multi-camera.
+     */
+    vec<PhysicalCameraMetadata> physicalCameraMetadata;
+};
diff --git a/camera/device/README.md b/camera/device/README.md
index 9f60781..3709cb8 100644
--- a/camera/device/README.md
+++ b/camera/device/README.md
@@ -87,3 +87,11 @@
     supported in the legacy camera HAL.
 
 Added in Android 8.1.
+
+### ICameraDevice.hal@3.4:
+
+A minor revision to the ICameraDevice.hal@3.3.
+
+  - Adds support for session parameters during stream configuration.
+
+Added in Android 9
diff --git a/camera/metadata/3.2/docs.html b/camera/metadata/3.2/docs.html
deleted file mode 100644
index 004ecae..0000000
--- a/camera/metadata/3.2/docs.html
+++ /dev/null
@@ -1,27340 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!-- Copyright (C) 2012 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.
--->
-<head>
-  <!-- automatically generated from html.mako. do NOT edit directly -->
-  <meta charset="utf-8" />
-  <title>Android Camera HAL3.4 Properties</title>
-  <style type="text/css">
-     body { background-color: #f7f7f7; font-family: Roboto, sans-serif;}
-     h1 { color: #333333; }
-     h2 { color: #333333; }
-     a:link { color: #258aaf; text-decoration: none}
-     a:hover { color: #459aaf; text-decoration: underline }
-     a:visited { color: #154a5f; text-decoration: none}
-    .section { color: #eeeeee; font-size: 1.5em; font-weight: bold; background-color: #888888; padding: 0.5em 0em 0.5em 0.5em; border-width: thick thin thin thin; border-color: #111111 #777777 #777777 #777777}
-    .kind { color: #eeeeee; font-size: 1.2em; font-weight: bold; padding-left: 1.5em; background-color: #aaaaaa }
-    .entry { background-color: #f0f0f0 }
-    .entry_cont { background-color: #f0f0f0 }
-    .entries_header { background-color: #dddddd; text-align: center}
-
-    /* toc style */
-    .toc_section_header { font-size:1.3em;  }
-    .toc_kind_header { font-size:1.2em;  }
-    .toc_deprecated { text-decoration:line-through; }
-
-    /* table column sizes */
-    table { border-collapse:collapse; table-layout: fixed; width: 100%; word-wrap: break-word }
-    td,th { border: 1px solid; border-color: #aaaaaa; padding-left: 0.5em; padding-right: 0.5em }
-    .th_name { width: 20% }
-    .th_units { width: 10% }
-    .th_tags { width: 5% }
-    .th_details { width: 25% }
-    .th_type { width: 20% }
-    .th_description { width: 20% }
-    .th_range { width: 10% }
-    td { font-size: 0.9em; }
-
-    /* hide the first thead, we need it there only to enforce column sizes */
-    .thead_dummy { visibility: hidden; }
-
-    /* Entry flair */
-    .entry_name { color: #333333; padding-left:1.0em; font-size:1.1em; font-family: monospace; vertical-align:top; }
-    .entry_name_deprecated { text-decoration:line-through; }
-
-    /* Entry type flair */
-    .entry_type_name { font-size:1.1em; color: #669900; font-weight: bold;}
-    .entry_type_name_enum:after { color: #669900; font-weight: bold; content:" (enum)" }
-    .entry_type_visibility { font-weight: bolder; padding-left:1em}
-    .entry_type_synthetic { font-weight: bolder; color: #996600; }
-    .entry_type_hwlevel { font-weight: bolder; color: #000066; }
-    .entry_type_deprecated { font-weight: bolder; color: #4D4D4D; }
-    .entry_type_enum_name { font-family: monospace; font-weight: bolder; }
-    .entry_type_enum_notes:before { content:" - " }
-    .entry_type_enum_notes>p:first-child { display:inline; }
-    .entry_type_enum_value:before { content:" = " }
-    .entry_type_enum_value { font-family: monospace; }
-    .entry ul { margin: 0 0 0 0; list-style-position: inside; padding-left: 0.5em; }
-    .entry ul li { padding: 0 0 0 0; margin: 0 0 0 0;}
-    .entry_range_deprecated { font-weight: bolder; }
-
-    /* Entry tags flair */
-    .entry_tags ul { list-style-type: none; }
-
-    /* Entry details (full docs) flair */
-    .entry_details_header { font-weight: bold; background-color: #dddddd;
-      text-align: center; font-size: 1.1em; margin-left: 0em; margin-right: 0em; }
-
-    /* Entry spacer flair */
-    .entry_spacer { background-color: transparent; border-style: none; height: 0.5em; }
-
-    /* TODO: generate abbr element for each tag link? */
-    /* TODO for each x.y.z try to link it to the entry */
-
-  </style>
-
-  <style>
-
-    {
-      /* broken...
-         supposedly there is a bug in chrome that it lays out tables before
-         it knows its being printed, so the page-break-* styles are ignored
-         */
-        tr { page-break-after: always; page-break-inside: avoid; }
-    }
-
-  </style>
-</head>
-
-
-
-<body>
-  <h1>Android Camera HAL3.2 Properties</h1>
-
-
-  <h2>Table of Contents</h2>
-  <ul class="toc">
-    <li><a href="#tag_index" class="toc_section_header">Tags</a></li>
-    <li>
-      <span class="toc_section_header"><a href="#section_colorCorrection">colorCorrection</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.colorCorrection.mode">android.colorCorrection.mode</a></li>
-            <li
-            ><a href="#controls_android.colorCorrection.transform">android.colorCorrection.transform</a></li>
-            <li
-            ><a href="#controls_android.colorCorrection.gains">android.colorCorrection.gains</a></li>
-            <li
-            ><a href="#controls_android.colorCorrection.aberrationMode">android.colorCorrection.aberrationMode</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.colorCorrection.mode">android.colorCorrection.mode</a></li>
-            <li
-            ><a href="#dynamic_android.colorCorrection.transform">android.colorCorrection.transform</a></li>
-            <li
-            ><a href="#dynamic_android.colorCorrection.gains">android.colorCorrection.gains</a></li>
-            <li
-            ><a href="#dynamic_android.colorCorrection.aberrationMode">android.colorCorrection.aberrationMode</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.colorCorrection.availableAberrationModes">android.colorCorrection.availableAberrationModes</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_control">control</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.control.aeAntibandingMode">android.control.aeAntibandingMode</a></li>
-            <li
-            ><a href="#controls_android.control.aeExposureCompensation">android.control.aeExposureCompensation</a></li>
-            <li
-            ><a href="#controls_android.control.aeLock">android.control.aeLock</a></li>
-            <li
-            ><a href="#controls_android.control.aeMode">android.control.aeMode</a></li>
-            <li
-            ><a href="#controls_android.control.aeRegions">android.control.aeRegions</a></li>
-            <li
-            ><a href="#controls_android.control.aeTargetFpsRange">android.control.aeTargetFpsRange</a></li>
-            <li
-            ><a href="#controls_android.control.aePrecaptureTrigger">android.control.aePrecaptureTrigger</a></li>
-            <li
-            ><a href="#controls_android.control.afMode">android.control.afMode</a></li>
-            <li
-            ><a href="#controls_android.control.afRegions">android.control.afRegions</a></li>
-            <li
-            ><a href="#controls_android.control.afTrigger">android.control.afTrigger</a></li>
-            <li
-            ><a href="#controls_android.control.awbLock">android.control.awbLock</a></li>
-            <li
-            ><a href="#controls_android.control.awbMode">android.control.awbMode</a></li>
-            <li
-            ><a href="#controls_android.control.awbRegions">android.control.awbRegions</a></li>
-            <li
-            ><a href="#controls_android.control.captureIntent">android.control.captureIntent</a></li>
-            <li
-            ><a href="#controls_android.control.effectMode">android.control.effectMode</a></li>
-            <li
-            ><a href="#controls_android.control.mode">android.control.mode</a></li>
-            <li
-            ><a href="#controls_android.control.sceneMode">android.control.sceneMode</a></li>
-            <li
-            ><a href="#controls_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a></li>
-            <li
-            ><a href="#controls_android.control.postRawSensitivityBoost">android.control.postRawSensitivityBoost</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.control.aeAvailableAntibandingModes">android.control.aeAvailableAntibandingModes</a></li>
-            <li
-            ><a href="#static_android.control.aeAvailableModes">android.control.aeAvailableModes</a></li>
-            <li
-            ><a href="#static_android.control.aeAvailableTargetFpsRanges">android.control.aeAvailableTargetFpsRanges</a></li>
-            <li
-            ><a href="#static_android.control.aeCompensationRange">android.control.aeCompensationRange</a></li>
-            <li
-            ><a href="#static_android.control.aeCompensationStep">android.control.aeCompensationStep</a></li>
-            <li
-            ><a href="#static_android.control.afAvailableModes">android.control.afAvailableModes</a></li>
-            <li
-            ><a href="#static_android.control.availableEffects">android.control.availableEffects</a></li>
-            <li
-            ><a href="#static_android.control.availableSceneModes">android.control.availableSceneModes</a></li>
-            <li
-            ><a href="#static_android.control.availableVideoStabilizationModes">android.control.availableVideoStabilizationModes</a></li>
-            <li
-            ><a href="#static_android.control.awbAvailableModes">android.control.awbAvailableModes</a></li>
-            <li
-            ><a href="#static_android.control.maxRegions">android.control.maxRegions</a></li>
-            <li
-            ><a href="#static_android.control.maxRegionsAe">android.control.maxRegionsAe</a></li>
-            <li
-            ><a href="#static_android.control.maxRegionsAwb">android.control.maxRegionsAwb</a></li>
-            <li
-            ><a href="#static_android.control.maxRegionsAf">android.control.maxRegionsAf</a></li>
-            <li
-            ><a href="#static_android.control.sceneModeOverrides">android.control.sceneModeOverrides</a></li>
-            <li
-            ><a href="#static_android.control.availableHighSpeedVideoConfigurations">android.control.availableHighSpeedVideoConfigurations</a></li>
-            <li
-            ><a href="#static_android.control.aeLockAvailable">android.control.aeLockAvailable</a></li>
-            <li
-            ><a href="#static_android.control.awbLockAvailable">android.control.awbLockAvailable</a></li>
-            <li
-            ><a href="#static_android.control.availableModes">android.control.availableModes</a></li>
-            <li
-            ><a href="#static_android.control.postRawSensitivityBoostRange">android.control.postRawSensitivityBoostRange</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-                class="toc_deprecated"
-            ><a href="#dynamic_android.control.aePrecaptureId">android.control.aePrecaptureId</a></li>
-            <li
-            ><a href="#dynamic_android.control.aeAntibandingMode">android.control.aeAntibandingMode</a></li>
-            <li
-            ><a href="#dynamic_android.control.aeExposureCompensation">android.control.aeExposureCompensation</a></li>
-            <li
-            ><a href="#dynamic_android.control.aeLock">android.control.aeLock</a></li>
-            <li
-            ><a href="#dynamic_android.control.aeMode">android.control.aeMode</a></li>
-            <li
-            ><a href="#dynamic_android.control.aeRegions">android.control.aeRegions</a></li>
-            <li
-            ><a href="#dynamic_android.control.aeTargetFpsRange">android.control.aeTargetFpsRange</a></li>
-            <li
-            ><a href="#dynamic_android.control.aePrecaptureTrigger">android.control.aePrecaptureTrigger</a></li>
-            <li
-            ><a href="#dynamic_android.control.aeState">android.control.aeState</a></li>
-            <li
-            ><a href="#dynamic_android.control.afMode">android.control.afMode</a></li>
-            <li
-            ><a href="#dynamic_android.control.afRegions">android.control.afRegions</a></li>
-            <li
-            ><a href="#dynamic_android.control.afTrigger">android.control.afTrigger</a></li>
-            <li
-            ><a href="#dynamic_android.control.afState">android.control.afState</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#dynamic_android.control.afTriggerId">android.control.afTriggerId</a></li>
-            <li
-            ><a href="#dynamic_android.control.awbLock">android.control.awbLock</a></li>
-            <li
-            ><a href="#dynamic_android.control.awbMode">android.control.awbMode</a></li>
-            <li
-            ><a href="#dynamic_android.control.awbRegions">android.control.awbRegions</a></li>
-            <li
-            ><a href="#dynamic_android.control.captureIntent">android.control.captureIntent</a></li>
-            <li
-            ><a href="#dynamic_android.control.awbState">android.control.awbState</a></li>
-            <li
-            ><a href="#dynamic_android.control.effectMode">android.control.effectMode</a></li>
-            <li
-            ><a href="#dynamic_android.control.mode">android.control.mode</a></li>
-            <li
-            ><a href="#dynamic_android.control.sceneMode">android.control.sceneMode</a></li>
-            <li
-            ><a href="#dynamic_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a></li>
-            <li
-            ><a href="#dynamic_android.control.postRawSensitivityBoost">android.control.postRawSensitivityBoost</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_demosaic">demosaic</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.demosaic.mode">android.demosaic.mode</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_edge">edge</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.edge.mode">android.edge.mode</a></li>
-            <li
-            ><a href="#controls_android.edge.strength">android.edge.strength</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.edge.availableEdgeModes">android.edge.availableEdgeModes</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.edge.mode">android.edge.mode</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_flash">flash</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.flash.firingPower">android.flash.firingPower</a></li>
-            <li
-            ><a href="#controls_android.flash.firingTime">android.flash.firingTime</a></li>
-            <li
-            ><a href="#controls_android.flash.mode">android.flash.mode</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-
-            <li
-            ><a href="#static_android.flash.info.available">android.flash.info.available</a></li>
-            <li
-            ><a href="#static_android.flash.info.chargeDuration">android.flash.info.chargeDuration</a></li>
-
-            <li
-            ><a href="#static_android.flash.colorTemperature">android.flash.colorTemperature</a></li>
-            <li
-            ><a href="#static_android.flash.maxEnergy">android.flash.maxEnergy</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.flash.firingPower">android.flash.firingPower</a></li>
-            <li
-            ><a href="#dynamic_android.flash.firingTime">android.flash.firingTime</a></li>
-            <li
-            ><a href="#dynamic_android.flash.mode">android.flash.mode</a></li>
-            <li
-            ><a href="#dynamic_android.flash.state">android.flash.state</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_hotPixel">hotPixel</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.hotPixel.mode">android.hotPixel.mode</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.hotPixel.availableHotPixelModes">android.hotPixel.availableHotPixelModes</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.hotPixel.mode">android.hotPixel.mode</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_jpeg">jpeg</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.jpeg.gpsLocation">android.jpeg.gpsLocation</a></li>
-            <li
-            ><a href="#controls_android.jpeg.gpsCoordinates">android.jpeg.gpsCoordinates</a></li>
-            <li
-            ><a href="#controls_android.jpeg.gpsProcessingMethod">android.jpeg.gpsProcessingMethod</a></li>
-            <li
-            ><a href="#controls_android.jpeg.gpsTimestamp">android.jpeg.gpsTimestamp</a></li>
-            <li
-            ><a href="#controls_android.jpeg.orientation">android.jpeg.orientation</a></li>
-            <li
-            ><a href="#controls_android.jpeg.quality">android.jpeg.quality</a></li>
-            <li
-            ><a href="#controls_android.jpeg.thumbnailQuality">android.jpeg.thumbnailQuality</a></li>
-            <li
-            ><a href="#controls_android.jpeg.thumbnailSize">android.jpeg.thumbnailSize</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.jpeg.availableThumbnailSizes">android.jpeg.availableThumbnailSizes</a></li>
-            <li
-            ><a href="#static_android.jpeg.maxSize">android.jpeg.maxSize</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.jpeg.gpsLocation">android.jpeg.gpsLocation</a></li>
-            <li
-            ><a href="#dynamic_android.jpeg.gpsCoordinates">android.jpeg.gpsCoordinates</a></li>
-            <li
-            ><a href="#dynamic_android.jpeg.gpsProcessingMethod">android.jpeg.gpsProcessingMethod</a></li>
-            <li
-            ><a href="#dynamic_android.jpeg.gpsTimestamp">android.jpeg.gpsTimestamp</a></li>
-            <li
-            ><a href="#dynamic_android.jpeg.orientation">android.jpeg.orientation</a></li>
-            <li
-            ><a href="#dynamic_android.jpeg.quality">android.jpeg.quality</a></li>
-            <li
-            ><a href="#dynamic_android.jpeg.size">android.jpeg.size</a></li>
-            <li
-            ><a href="#dynamic_android.jpeg.thumbnailQuality">android.jpeg.thumbnailQuality</a></li>
-            <li
-            ><a href="#dynamic_android.jpeg.thumbnailSize">android.jpeg.thumbnailSize</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_lens">lens</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.lens.aperture">android.lens.aperture</a></li>
-            <li
-            ><a href="#controls_android.lens.filterDensity">android.lens.filterDensity</a></li>
-            <li
-            ><a href="#controls_android.lens.focalLength">android.lens.focalLength</a></li>
-            <li
-            ><a href="#controls_android.lens.focusDistance">android.lens.focusDistance</a></li>
-            <li
-            ><a href="#controls_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-
-            <li
-            ><a href="#static_android.lens.info.availableApertures">android.lens.info.availableApertures</a></li>
-            <li
-            ><a href="#static_android.lens.info.availableFilterDensities">android.lens.info.availableFilterDensities</a></li>
-            <li
-            ><a href="#static_android.lens.info.availableFocalLengths">android.lens.info.availableFocalLengths</a></li>
-            <li
-            ><a href="#static_android.lens.info.availableOpticalStabilization">android.lens.info.availableOpticalStabilization</a></li>
-            <li
-            ><a href="#static_android.lens.info.hyperfocalDistance">android.lens.info.hyperfocalDistance</a></li>
-            <li
-            ><a href="#static_android.lens.info.minimumFocusDistance">android.lens.info.minimumFocusDistance</a></li>
-            <li
-            ><a href="#static_android.lens.info.shadingMapSize">android.lens.info.shadingMapSize</a></li>
-            <li
-            ><a href="#static_android.lens.info.focusDistanceCalibration">android.lens.info.focusDistanceCalibration</a></li>
-
-            <li
-            ><a href="#static_android.lens.facing">android.lens.facing</a></li>
-            <li
-            ><a href="#static_android.lens.poseRotation">android.lens.poseRotation</a></li>
-            <li
-            ><a href="#static_android.lens.poseTranslation">android.lens.poseTranslation</a></li>
-            <li
-            ><a href="#static_android.lens.intrinsicCalibration">android.lens.intrinsicCalibration</a></li>
-            <li
-            ><a href="#static_android.lens.radialDistortion">android.lens.radialDistortion</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.lens.aperture">android.lens.aperture</a></li>
-            <li
-            ><a href="#dynamic_android.lens.filterDensity">android.lens.filterDensity</a></li>
-            <li
-            ><a href="#dynamic_android.lens.focalLength">android.lens.focalLength</a></li>
-            <li
-            ><a href="#dynamic_android.lens.focusDistance">android.lens.focusDistance</a></li>
-            <li
-            ><a href="#dynamic_android.lens.focusRange">android.lens.focusRange</a></li>
-            <li
-            ><a href="#dynamic_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a></li>
-            <li
-            ><a href="#dynamic_android.lens.state">android.lens.state</a></li>
-            <li
-            ><a href="#dynamic_android.lens.poseRotation">android.lens.poseRotation</a></li>
-            <li
-            ><a href="#dynamic_android.lens.poseTranslation">android.lens.poseTranslation</a></li>
-            <li
-            ><a href="#dynamic_android.lens.intrinsicCalibration">android.lens.intrinsicCalibration</a></li>
-            <li
-            ><a href="#dynamic_android.lens.radialDistortion">android.lens.radialDistortion</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_noiseReduction">noiseReduction</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.noiseReduction.mode">android.noiseReduction.mode</a></li>
-            <li
-            ><a href="#controls_android.noiseReduction.strength">android.noiseReduction.strength</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.noiseReduction.availableNoiseReductionModes</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.noiseReduction.mode">android.noiseReduction.mode</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_quirks">quirks</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.quirks.meteringCropRegion">android.quirks.meteringCropRegion</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.quirks.triggerAfWithAuto">android.quirks.triggerAfWithAuto</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.quirks.useZslFormat">android.quirks.useZslFormat</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.quirks.usePartialResult">android.quirks.usePartialResult</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-                class="toc_deprecated"
-            ><a href="#dynamic_android.quirks.partialResult">android.quirks.partialResult</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_request">request</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-                class="toc_deprecated"
-            ><a href="#controls_android.request.frameCount">android.request.frameCount</a></li>
-            <li
-            ><a href="#controls_android.request.id">android.request.id</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#controls_android.request.inputStreams">android.request.inputStreams</a></li>
-            <li
-            ><a href="#controls_android.request.metadataMode">android.request.metadataMode</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#controls_android.request.outputStreams">android.request.outputStreams</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#controls_android.request.type">android.request.type</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.request.maxNumOutputStreams">android.request.maxNumOutputStreams</a></li>
-            <li
-            ><a href="#static_android.request.maxNumOutputRaw">android.request.maxNumOutputRaw</a></li>
-            <li
-            ><a href="#static_android.request.maxNumOutputProc">android.request.maxNumOutputProc</a></li>
-            <li
-            ><a href="#static_android.request.maxNumOutputProcStalling">android.request.maxNumOutputProcStalling</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.request.maxNumReprocessStreams">android.request.maxNumReprocessStreams</a></li>
-            <li
-            ><a href="#static_android.request.maxNumInputStreams">android.request.maxNumInputStreams</a></li>
-            <li
-            ><a href="#static_android.request.pipelineMaxDepth">android.request.pipelineMaxDepth</a></li>
-            <li
-            ><a href="#static_android.request.partialResultCount">android.request.partialResultCount</a></li>
-            <li
-            ><a href="#static_android.request.availableCapabilities">android.request.availableCapabilities</a></li>
-            <li
-            ><a href="#static_android.request.availableRequestKeys">android.request.availableRequestKeys</a></li>
-            <li
-            ><a href="#static_android.request.availableResultKeys">android.request.availableResultKeys</a></li>
-            <li
-            ><a href="#static_android.request.availableCharacteristicsKeys">android.request.availableCharacteristicsKeys</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-                class="toc_deprecated"
-            ><a href="#dynamic_android.request.frameCount">android.request.frameCount</a></li>
-            <li
-            ><a href="#dynamic_android.request.id">android.request.id</a></li>
-            <li
-            ><a href="#dynamic_android.request.metadataMode">android.request.metadataMode</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#dynamic_android.request.outputStreams">android.request.outputStreams</a></li>
-            <li
-            ><a href="#dynamic_android.request.pipelineDepth">android.request.pipelineDepth</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_scaler">scaler</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.scaler.cropRegion">android.scaler.cropRegion</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.scaler.availableFormats">android.scaler.availableFormats</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.scaler.availableJpegMinDurations">android.scaler.availableJpegMinDurations</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.scaler.availableJpegSizes">android.scaler.availableJpegSizes</a></li>
-            <li
-            ><a href="#static_android.scaler.availableMaxDigitalZoom">android.scaler.availableMaxDigitalZoom</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.scaler.availableProcessedMinDurations">android.scaler.availableProcessedMinDurations</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.scaler.availableProcessedSizes">android.scaler.availableProcessedSizes</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.scaler.availableRawMinDurations">android.scaler.availableRawMinDurations</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#static_android.scaler.availableRawSizes">android.scaler.availableRawSizes</a></li>
-            <li
-            ><a href="#static_android.scaler.availableInputOutputFormatsMap">android.scaler.availableInputOutputFormatsMap</a></li>
-            <li
-            ><a href="#static_android.scaler.availableStreamConfigurations">android.scaler.availableStreamConfigurations</a></li>
-            <li
-            ><a href="#static_android.scaler.availableMinFrameDurations">android.scaler.availableMinFrameDurations</a></li>
-            <li
-            ><a href="#static_android.scaler.availableStallDurations">android.scaler.availableStallDurations</a></li>
-            <li
-            ><a href="#static_android.scaler.streamConfigurationMap">android.scaler.streamConfigurationMap</a></li>
-            <li
-            ><a href="#static_android.scaler.croppingType">android.scaler.croppingType</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.scaler.cropRegion">android.scaler.cropRegion</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_sensor">sensor</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.sensor.exposureTime">android.sensor.exposureTime</a></li>
-            <li
-            ><a href="#controls_android.sensor.frameDuration">android.sensor.frameDuration</a></li>
-            <li
-            ><a href="#controls_android.sensor.sensitivity">android.sensor.sensitivity</a></li>
-            <li
-            ><a href="#controls_android.sensor.testPatternData">android.sensor.testPatternData</a></li>
-            <li
-            ><a href="#controls_android.sensor.testPatternMode">android.sensor.testPatternMode</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-
-            <li
-            ><a href="#static_android.sensor.info.activeArraySize">android.sensor.info.activeArraySize</a></li>
-            <li
-            ><a href="#static_android.sensor.info.sensitivityRange">android.sensor.info.sensitivityRange</a></li>
-            <li
-            ><a href="#static_android.sensor.info.colorFilterArrangement">android.sensor.info.colorFilterArrangement</a></li>
-            <li
-            ><a href="#static_android.sensor.info.exposureTimeRange">android.sensor.info.exposureTimeRange</a></li>
-            <li
-            ><a href="#static_android.sensor.info.maxFrameDuration">android.sensor.info.maxFrameDuration</a></li>
-            <li
-            ><a href="#static_android.sensor.info.physicalSize">android.sensor.info.physicalSize</a></li>
-            <li
-            ><a href="#static_android.sensor.info.pixelArraySize">android.sensor.info.pixelArraySize</a></li>
-            <li
-            ><a href="#static_android.sensor.info.whiteLevel">android.sensor.info.whiteLevel</a></li>
-            <li
-            ><a href="#static_android.sensor.info.timestampSource">android.sensor.info.timestampSource</a></li>
-            <li
-            ><a href="#static_android.sensor.info.lensShadingApplied">android.sensor.info.lensShadingApplied</a></li>
-            <li
-            ><a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.sensor.info.preCorrectionActiveArraySize</a></li>
-
-            <li
-            ><a href="#static_android.sensor.referenceIlluminant1">android.sensor.referenceIlluminant1</a></li>
-            <li
-            ><a href="#static_android.sensor.referenceIlluminant2">android.sensor.referenceIlluminant2</a></li>
-            <li
-            ><a href="#static_android.sensor.calibrationTransform1">android.sensor.calibrationTransform1</a></li>
-            <li
-            ><a href="#static_android.sensor.calibrationTransform2">android.sensor.calibrationTransform2</a></li>
-            <li
-            ><a href="#static_android.sensor.colorTransform1">android.sensor.colorTransform1</a></li>
-            <li
-            ><a href="#static_android.sensor.colorTransform2">android.sensor.colorTransform2</a></li>
-            <li
-            ><a href="#static_android.sensor.forwardMatrix1">android.sensor.forwardMatrix1</a></li>
-            <li
-            ><a href="#static_android.sensor.forwardMatrix2">android.sensor.forwardMatrix2</a></li>
-            <li
-            ><a href="#static_android.sensor.baseGainFactor">android.sensor.baseGainFactor</a></li>
-            <li
-            ><a href="#static_android.sensor.blackLevelPattern">android.sensor.blackLevelPattern</a></li>
-            <li
-            ><a href="#static_android.sensor.maxAnalogSensitivity">android.sensor.maxAnalogSensitivity</a></li>
-            <li
-            ><a href="#static_android.sensor.orientation">android.sensor.orientation</a></li>
-            <li
-            ><a href="#static_android.sensor.profileHueSatMapDimensions">android.sensor.profileHueSatMapDimensions</a></li>
-            <li
-            ><a href="#static_android.sensor.availableTestPatternModes">android.sensor.availableTestPatternModes</a></li>
-            <li
-            ><a href="#static_android.sensor.opticalBlackRegions">android.sensor.opticalBlackRegions</a></li>
-            <li
-            ><a href="#static_android.sensor.opaqueRawSize">android.sensor.opaqueRawSize</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.sensor.exposureTime">android.sensor.exposureTime</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.frameDuration">android.sensor.frameDuration</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.sensitivity">android.sensor.sensitivity</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.timestamp">android.sensor.timestamp</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.temperature">android.sensor.temperature</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.neutralColorPoint">android.sensor.neutralColorPoint</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.noiseProfile">android.sensor.noiseProfile</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.profileHueSatMap">android.sensor.profileHueSatMap</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.profileToneCurve">android.sensor.profileToneCurve</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.greenSplit">android.sensor.greenSplit</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.testPatternData">android.sensor.testPatternData</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.testPatternMode">android.sensor.testPatternMode</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.rollingShutterSkew">android.sensor.rollingShutterSkew</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.dynamicBlackLevel">android.sensor.dynamicBlackLevel</a></li>
-            <li
-            ><a href="#dynamic_android.sensor.dynamicWhiteLevel">android.sensor.dynamicWhiteLevel</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_shading">shading</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.shading.mode">android.shading.mode</a></li>
-            <li
-            ><a href="#controls_android.shading.strength">android.shading.strength</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.shading.mode">android.shading.mode</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.shading.availableModes">android.shading.availableModes</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_statistics">statistics</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.statistics.faceDetectMode">android.statistics.faceDetectMode</a></li>
-            <li
-            ><a href="#controls_android.statistics.histogramMode">android.statistics.histogramMode</a></li>
-            <li
-            ><a href="#controls_android.statistics.sharpnessMapMode">android.statistics.sharpnessMapMode</a></li>
-            <li
-            ><a href="#controls_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a></li>
-            <li
-            ><a href="#controls_android.statistics.lensShadingMapMode">android.statistics.lensShadingMapMode</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-
-            <li
-            ><a href="#static_android.statistics.info.availableFaceDetectModes">android.statistics.info.availableFaceDetectModes</a></li>
-            <li
-            ><a href="#static_android.statistics.info.histogramBucketCount">android.statistics.info.histogramBucketCount</a></li>
-            <li
-            ><a href="#static_android.statistics.info.maxFaceCount">android.statistics.info.maxFaceCount</a></li>
-            <li
-            ><a href="#static_android.statistics.info.maxHistogramCount">android.statistics.info.maxHistogramCount</a></li>
-            <li
-            ><a href="#static_android.statistics.info.maxSharpnessMapValue">android.statistics.info.maxSharpnessMapValue</a></li>
-            <li
-            ><a href="#static_android.statistics.info.sharpnessMapSize">android.statistics.info.sharpnessMapSize</a></li>
-            <li
-            ><a href="#static_android.statistics.info.availableHotPixelMapModes">android.statistics.info.availableHotPixelMapModes</a></li>
-            <li
-            ><a href="#static_android.statistics.info.availableLensShadingMapModes">android.statistics.info.availableLensShadingMapModes</a></li>
-
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.statistics.faceDetectMode">android.statistics.faceDetectMode</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.faceIds">android.statistics.faceIds</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.faceLandmarks">android.statistics.faceLandmarks</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.faceRectangles">android.statistics.faceRectangles</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.faceScores">android.statistics.faceScores</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.faces">android.statistics.faces</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.histogram">android.statistics.histogram</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.histogramMode">android.statistics.histogramMode</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.sharpnessMap">android.statistics.sharpnessMap</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.sharpnessMapMode">android.statistics.sharpnessMapMode</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.statistics.lensShadingCorrectionMap</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.lensShadingMap">android.statistics.lensShadingMap</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#dynamic_android.statistics.predictedColorGains">android.statistics.predictedColorGains</a></li>
-            <li
-                class="toc_deprecated"
-            ><a href="#dynamic_android.statistics.predictedColorTransform">android.statistics.predictedColorTransform</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.sceneFlicker">android.statistics.sceneFlicker</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.hotPixelMap">android.statistics.hotPixelMap</a></li>
-            <li
-            ><a href="#dynamic_android.statistics.lensShadingMapMode">android.statistics.lensShadingMapMode</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_tonemap">tonemap</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.tonemap.curveBlue">android.tonemap.curveBlue</a></li>
-            <li
-            ><a href="#controls_android.tonemap.curveGreen">android.tonemap.curveGreen</a></li>
-            <li
-            ><a href="#controls_android.tonemap.curveRed">android.tonemap.curveRed</a></li>
-            <li
-            ><a href="#controls_android.tonemap.curve">android.tonemap.curve</a></li>
-            <li
-            ><a href="#controls_android.tonemap.mode">android.tonemap.mode</a></li>
-            <li
-            ><a href="#controls_android.tonemap.gamma">android.tonemap.gamma</a></li>
-            <li
-            ><a href="#controls_android.tonemap.presetCurve">android.tonemap.presetCurve</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.tonemap.maxCurvePoints">android.tonemap.maxCurvePoints</a></li>
-            <li
-            ><a href="#static_android.tonemap.availableToneMapModes">android.tonemap.availableToneMapModes</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.tonemap.curveBlue">android.tonemap.curveBlue</a></li>
-            <li
-            ><a href="#dynamic_android.tonemap.curveGreen">android.tonemap.curveGreen</a></li>
-            <li
-            ><a href="#dynamic_android.tonemap.curveRed">android.tonemap.curveRed</a></li>
-            <li
-            ><a href="#dynamic_android.tonemap.curve">android.tonemap.curve</a></li>
-            <li
-            ><a href="#dynamic_android.tonemap.mode">android.tonemap.mode</a></li>
-            <li
-            ><a href="#dynamic_android.tonemap.gamma">android.tonemap.gamma</a></li>
-            <li
-            ><a href="#dynamic_android.tonemap.presetCurve">android.tonemap.presetCurve</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_led">led</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.led.transmit">android.led.transmit</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.led.transmit">android.led.transmit</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.led.availableLeds">android.led.availableLeds</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_info">info</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.info.supportedHardwareLevel">android.info.supportedHardwareLevel</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_blackLevel">blackLevel</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.blackLevel.lock">android.blackLevel.lock</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.blackLevel.lock">android.blackLevel.lock</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_sync">sync</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.sync.frameNumber">android.sync.frameNumber</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.sync.maxLatency">android.sync.maxLatency</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_reprocess">reprocess</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">controls</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#controls_android.reprocess.effectiveExposureFactor">android.reprocess.effectiveExposureFactor</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">dynamic</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#dynamic_android.reprocess.effectiveExposureFactor">android.reprocess.effectiveExposureFactor</a></li>
-          </ul>
-        </li>
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.reprocess.maxCaptureStall">android.reprocess.maxCaptureStall</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-    <li>
-      <span class="toc_section_header"><a href="#section_depth">depth</a></span>
-      <ul class="toc_section">
-        <li>
-          <span class="toc_kind_header">static</span>
-          <ul class="toc_section">
-            <li
-            ><a href="#static_android.depth.maxDepthSamples">android.depth.maxDepthSamples</a></li>
-            <li
-            ><a href="#static_android.depth.availableDepthStreamConfigurations">android.depth.availableDepthStreamConfigurations</a></li>
-            <li
-            ><a href="#static_android.depth.availableDepthMinFrameDurations">android.depth.availableDepthMinFrameDurations</a></li>
-            <li
-            ><a href="#static_android.depth.availableDepthStallDurations">android.depth.availableDepthStallDurations</a></li>
-            <li
-            ><a href="#static_android.depth.depthIsExclusive">android.depth.depthIsExclusive</a></li>
-          </ul>
-        </li>
-      </ul> <!-- toc_section -->
-    </li>
-  </ul>
-
-
-  <h1>Properties</h1>
-  <table class="properties">
-
-    <thead class="thead_dummy">
-      <tr>
-        <th class="th_name">Property Name</th>
-        <th class="th_type">Type</th>
-        <th class="th_description">Description</th>
-        <th class="th_units">Units</th>
-        <th class="th_range">Range</th>
-        <th class="th_tags">Tags</th>
-      </tr>
-    </thead> <!-- so that the first occurrence of thead is not
-                         above the first occurrence of tr -->
-<!-- <namespace name="android"> -->
-  <tr><td colspan="6" id="section_colorCorrection" class="section">colorCorrection</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.colorCorrection.mode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>color<wbr/>Correction.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">TRANSFORM_MATRIX</span>
-                    <span class="entry_type_enum_notes"><p>Use the <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> matrix
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> to do color conversion.<wbr/></p>
-<p>All advanced white balance adjustments (not specified
-by our white balance pipeline) must be disabled.<wbr/></p>
-<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
-TRANSFORM_<wbr/>MATRIX is ignored.<wbr/> The camera device will override
-this value to either FAST or HIGH_<wbr/>QUALITY.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Color correction processing must not slow down
-capture rate relative to sensor raw output.<wbr/></p>
-<p>Advanced white balance adjustments above and beyond
-the specified white balance pipeline may be applied.<wbr/></p>
-<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
-the camera device uses the last frame's AWB values
-(or defaults if AWB has never been run).<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>Color correction processing operates at improved
-quality but the capture rate might be reduced (relative to sensor
-raw output rate)</p>
-<p>Advanced white balance adjustments above and beyond
-the specified white balance pipeline may be applied.<wbr/></p>
-<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
-the camera device uses the last frame's AWB values
-(or defaults if AWB has never been run).<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The mode control selects how the image data is converted from the
-sensor's native color into linear sRGB color.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When auto-white balance (AWB) is enabled with <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> this
-control is overridden by the AWB routine.<wbr/> When AWB is disabled,<wbr/> the
-application controls how the color mapping is performed.<wbr/></p>
-<p>We define the expected processing pipeline below.<wbr/> For consistency
-across devices,<wbr/> this is always the case with TRANSFORM_<wbr/>MATRIX.<wbr/></p>
-<p>When either FULL or HIGH_<wbr/>QUALITY is used,<wbr/> the camera device may
-do additional processing but <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
-<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> will still be provided by the
-camera device (in the results) and be roughly correct.<wbr/></p>
-<p>Switching to TRANSFORM_<wbr/>MATRIX and using the data provided from
-FAST or HIGH_<wbr/>QUALITY will yield a picture with the same white point
-as what was produced by the camera device in the earlier frame.<wbr/></p>
-<p>The expected processing pipeline is as follows:</p>
-<p><img alt="White balance processing pipeline" src="images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png"/></p>
-<p>The white balance is encoded by two values,<wbr/> a 4-channel white-balance
-gain vector (applied in the Bayer domain),<wbr/> and a 3x3 color transform
-matrix (applied after demosaic).<wbr/></p>
-<p>The 4-channel white-balance gains are defined as:</p>
-<pre><code><a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> = [ R G_<wbr/>even G_<wbr/>odd B ]
-</code></pre>
-<p>where <code>G_<wbr/>even</code> is the gain for green pixels on even rows of the
-output,<wbr/> and <code>G_<wbr/>odd</code> is the gain for green pixels on the odd rows.<wbr/>
-These may be identical for a given camera device implementation; if
-the camera device does not support a separate gain for even/<wbr/>odd green
-channels,<wbr/> it will use the <code>G_<wbr/>even</code> value,<wbr/> and write <code>G_<wbr/>odd</code> equal to
-<code>G_<wbr/>even</code> in the output result metadata.<wbr/></p>
-<p>The matrices for color transforms are defined as a 9-entry vector:</p>
-<pre><code><a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> = [ I0 I1 I2 I3 I4 I5 I6 I7 I8 ]
-</code></pre>
-<p>which define a transform from input sensor colors,<wbr/> <code>P_<wbr/>in = [ r g b ]</code>,<wbr/>
-to output linear sRGB,<wbr/> <code>P_<wbr/>out = [ r' g' b' ]</code>,<wbr/></p>
-<p>with colors as follows:</p>
-<pre><code>r' = I0r + I1g + I2b
-g' = I3r + I4g + I5b
-b' = I6r + I7g + I8b
-</code></pre>
-<p>Both the input and output value ranges must match.<wbr/> Overflow/<wbr/>underflow
-values are clipped to fit within the range.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if color correction control is available
-on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
-That is,<wbr/> if the highest quality implementation on the camera device does not slow down
-capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY should generate the same output.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.colorCorrection.transform">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>color<wbr/>Correction.<wbr/>transform
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3 x 3
-                </span>
-              <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">3x3 rational matrix in row-major order</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A color transform matrix to use to transform
-from sensor RGB color space to output linear sRGB color space.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Unitless scale factors
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This matrix is either set by the camera device when the request
-<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not TRANSFORM_<wbr/>MATRIX,<wbr/> or
-directly by the application in the request when the
-<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is TRANSFORM_<wbr/>MATRIX.<wbr/></p>
-<p>In the latter case,<wbr/> the camera device may round the matrix to account
-for precision issues; the final rounded matrix should be reported back
-in this matrix result metadata.<wbr/> The transform should keep the magnitude
-of the output color values within <code>[0,<wbr/> 1.<wbr/>0]</code> (assuming input color
-values is within the normalized range <code>[0,<wbr/> 1.<wbr/>0]</code>),<wbr/> or clipping may occur.<wbr/></p>
-<p>The valid range of each matrix element varies on different devices,<wbr/> but
-values within [-1.<wbr/>5,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.colorCorrection.gains">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>color<wbr/>Correction.<wbr/>gains
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public as rggbChannelVector]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">A 1D array of floats for 4 color channel gains</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Gains applying to Bayer raw color channels for
-white-balance.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Unitless gain factors
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>These per-channel gains are either set by the camera device
-when the request <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not
-TRANSFORM_<wbr/>MATRIX,<wbr/> or directly by the application in the
-request when the <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is
-TRANSFORM_<wbr/>MATRIX.<wbr/></p>
-<p>The gains in the result metadata are the gains actually
-applied by the camera device to the current frame.<wbr/></p>
-<p>The valid range of gains varies on different devices,<wbr/> but gains
-between [1.<wbr/>0,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/> Even if a given
-device allows gains below 1.<wbr/>0,<wbr/> this is usually not recommended because
-this can create color artifacts.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The 4-channel white-balance gains are defined in
-the order of <code>[R G_<wbr/>even G_<wbr/>odd B]</code>,<wbr/> where <code>G_<wbr/>even</code> is the gain
-for green pixels on even rows of the output,<wbr/> and <code>G_<wbr/>odd</code>
-is the gain for green pixels on the odd rows.<wbr/></p>
-<p>If a HAL does not support a separate gain for even/<wbr/>odd green
-channels,<wbr/> it must use the <code>G_<wbr/>even</code> value,<wbr/> and write
-<code>G_<wbr/>odd</code> equal to <code>G_<wbr/>even</code> in the output result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.colorCorrection.aberrationMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No aberration correction is applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Aberration correction will not slow down capture rate
-relative to sensor raw output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>Aberration correction operates at improved quality but the capture rate might be
-reduced (relative to sensor raw output rate)</p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Mode of operation for the chromatic aberration correction algorithm.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.colorCorrection.availableAberrationModes">android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Chromatic (color) aberration is caused by the fact that different wavelengths of light
-can not focus on the same point after exiting from the lens.<wbr/> This metadata defines
-the high level control of chromatic aberration correction algorithm,<wbr/> which aims to
-minimize the chromatic artifacts that may occur along the object boundaries in an
-image.<wbr/></p>
-<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean that camera device determined aberration
-correction will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device will
-use the highest-quality aberration correction algorithms,<wbr/> even if it slows down
-capture rate.<wbr/> FAST means the camera device will not slow down capture rate when
-applying aberration correction.<wbr/></p>
-<p>LEGACY devices will always be in FAST mode.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.colorCorrection.mode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>color<wbr/>Correction.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">TRANSFORM_MATRIX</span>
-                    <span class="entry_type_enum_notes"><p>Use the <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> matrix
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> to do color conversion.<wbr/></p>
-<p>All advanced white balance adjustments (not specified
-by our white balance pipeline) must be disabled.<wbr/></p>
-<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
-TRANSFORM_<wbr/>MATRIX is ignored.<wbr/> The camera device will override
-this value to either FAST or HIGH_<wbr/>QUALITY.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Color correction processing must not slow down
-capture rate relative to sensor raw output.<wbr/></p>
-<p>Advanced white balance adjustments above and beyond
-the specified white balance pipeline may be applied.<wbr/></p>
-<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
-the camera device uses the last frame's AWB values
-(or defaults if AWB has never been run).<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>Color correction processing operates at improved
-quality but the capture rate might be reduced (relative to sensor
-raw output rate)</p>
-<p>Advanced white balance adjustments above and beyond
-the specified white balance pipeline may be applied.<wbr/></p>
-<p>If AWB is enabled with <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != OFF</code>,<wbr/> then
-the camera device uses the last frame's AWB values
-(or defaults if AWB has never been run).<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The mode control selects how the image data is converted from the
-sensor's native color into linear sRGB color.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When auto-white balance (AWB) is enabled with <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> this
-control is overridden by the AWB routine.<wbr/> When AWB is disabled,<wbr/> the
-application controls how the color mapping is performed.<wbr/></p>
-<p>We define the expected processing pipeline below.<wbr/> For consistency
-across devices,<wbr/> this is always the case with TRANSFORM_<wbr/>MATRIX.<wbr/></p>
-<p>When either FULL or HIGH_<wbr/>QUALITY is used,<wbr/> the camera device may
-do additional processing but <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
-<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> will still be provided by the
-camera device (in the results) and be roughly correct.<wbr/></p>
-<p>Switching to TRANSFORM_<wbr/>MATRIX and using the data provided from
-FAST or HIGH_<wbr/>QUALITY will yield a picture with the same white point
-as what was produced by the camera device in the earlier frame.<wbr/></p>
-<p>The expected processing pipeline is as follows:</p>
-<p><img alt="White balance processing pipeline" src="images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png"/></p>
-<p>The white balance is encoded by two values,<wbr/> a 4-channel white-balance
-gain vector (applied in the Bayer domain),<wbr/> and a 3x3 color transform
-matrix (applied after demosaic).<wbr/></p>
-<p>The 4-channel white-balance gains are defined as:</p>
-<pre><code><a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> = [ R G_<wbr/>even G_<wbr/>odd B ]
-</code></pre>
-<p>where <code>G_<wbr/>even</code> is the gain for green pixels on even rows of the
-output,<wbr/> and <code>G_<wbr/>odd</code> is the gain for green pixels on the odd rows.<wbr/>
-These may be identical for a given camera device implementation; if
-the camera device does not support a separate gain for even/<wbr/>odd green
-channels,<wbr/> it will use the <code>G_<wbr/>even</code> value,<wbr/> and write <code>G_<wbr/>odd</code> equal to
-<code>G_<wbr/>even</code> in the output result metadata.<wbr/></p>
-<p>The matrices for color transforms are defined as a 9-entry vector:</p>
-<pre><code><a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> = [ I0 I1 I2 I3 I4 I5 I6 I7 I8 ]
-</code></pre>
-<p>which define a transform from input sensor colors,<wbr/> <code>P_<wbr/>in = [ r g b ]</code>,<wbr/>
-to output linear sRGB,<wbr/> <code>P_<wbr/>out = [ r' g' b' ]</code>,<wbr/></p>
-<p>with colors as follows:</p>
-<pre><code>r' = I0r + I1g + I2b
-g' = I3r + I4g + I5b
-b' = I6r + I7g + I8b
-</code></pre>
-<p>Both the input and output value ranges must match.<wbr/> Overflow/<wbr/>underflow
-values are clipped to fit within the range.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if color correction control is available
-on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
-That is,<wbr/> if the highest quality implementation on the camera device does not slow down
-capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY should generate the same output.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.colorCorrection.transform">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>color<wbr/>Correction.<wbr/>transform
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3 x 3
-                </span>
-              <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">3x3 rational matrix in row-major order</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A color transform matrix to use to transform
-from sensor RGB color space to output linear sRGB color space.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Unitless scale factors
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This matrix is either set by the camera device when the request
-<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not TRANSFORM_<wbr/>MATRIX,<wbr/> or
-directly by the application in the request when the
-<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is TRANSFORM_<wbr/>MATRIX.<wbr/></p>
-<p>In the latter case,<wbr/> the camera device may round the matrix to account
-for precision issues; the final rounded matrix should be reported back
-in this matrix result metadata.<wbr/> The transform should keep the magnitude
-of the output color values within <code>[0,<wbr/> 1.<wbr/>0]</code> (assuming input color
-values is within the normalized range <code>[0,<wbr/> 1.<wbr/>0]</code>),<wbr/> or clipping may occur.<wbr/></p>
-<p>The valid range of each matrix element varies on different devices,<wbr/> but
-values within [-1.<wbr/>5,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.colorCorrection.gains">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>color<wbr/>Correction.<wbr/>gains
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public as rggbChannelVector]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">A 1D array of floats for 4 color channel gains</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Gains applying to Bayer raw color channels for
-white-balance.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Unitless gain factors
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>These per-channel gains are either set by the camera device
-when the request <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is not
-TRANSFORM_<wbr/>MATRIX,<wbr/> or directly by the application in the
-request when the <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> is
-TRANSFORM_<wbr/>MATRIX.<wbr/></p>
-<p>The gains in the result metadata are the gains actually
-applied by the camera device to the current frame.<wbr/></p>
-<p>The valid range of gains varies on different devices,<wbr/> but gains
-between [1.<wbr/>0,<wbr/> 3.<wbr/>0] are guaranteed not to be clipped.<wbr/> Even if a given
-device allows gains below 1.<wbr/>0,<wbr/> this is usually not recommended because
-this can create color artifacts.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The 4-channel white-balance gains are defined in
-the order of <code>[R G_<wbr/>even G_<wbr/>odd B]</code>,<wbr/> where <code>G_<wbr/>even</code> is the gain
-for green pixels on even rows of the output,<wbr/> and <code>G_<wbr/>odd</code>
-is the gain for green pixels on the odd rows.<wbr/></p>
-<p>If a HAL does not support a separate gain for even/<wbr/>odd green
-channels,<wbr/> it must use the <code>G_<wbr/>even</code> value,<wbr/> and write
-<code>G_<wbr/>odd</code> equal to <code>G_<wbr/>even</code> in the output result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.colorCorrection.aberrationMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No aberration correction is applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Aberration correction will not slow down capture rate
-relative to sensor raw output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>Aberration correction operates at improved quality but the capture rate might be
-reduced (relative to sensor raw output rate)</p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Mode of operation for the chromatic aberration correction algorithm.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.colorCorrection.availableAberrationModes">android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Chromatic (color) aberration is caused by the fact that different wavelengths of light
-can not focus on the same point after exiting from the lens.<wbr/> This metadata defines
-the high level control of chromatic aberration correction algorithm,<wbr/> which aims to
-minimize the chromatic artifacts that may occur along the object boundaries in an
-image.<wbr/></p>
-<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean that camera device determined aberration
-correction will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device will
-use the highest-quality aberration correction algorithms,<wbr/> even if it slows down
-capture rate.<wbr/> FAST means the camera device will not slow down capture rate when
-applying aberration correction.<wbr/></p>
-<p>LEGACY devices will always be in FAST mode.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.colorCorrection.availableAberrationModes">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of aberration correction modes for <a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a> that are
-supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This key lists the valid modes for <a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a>.<wbr/>  If no
-aberration correction modes are available for a device,<wbr/> this list will solely include
-OFF mode.<wbr/> All camera devices will support either OFF or FAST mode.<wbr/></p>
-<p>Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always list
-OFF mode.<wbr/> This includes all FULL level devices.<wbr/></p>
-<p>LEGACY devices will always only support FAST mode.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if chromatic aberration control is available
-on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
-That is,<wbr/> if the highest quality implementation on the camera device does not slow down
-capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_control" class="section">control</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.control.aeAntibandingMode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>The camera device will not adjust exposure duration to
-avoid banding problems.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">50HZ</span>
-                    <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to
-avoid banding problems with 50Hz illumination sources.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">60HZ</span>
-                    <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to
-avoid banding problems with 60Hz illumination
-sources.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">AUTO</span>
-                    <span class="entry_type_enum_notes"><p>The camera device will automatically adapt its
-antibanding routine to the current illumination
-condition.<wbr/> This is the default mode if AUTO is
-available on given camera device.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired setting for the camera device's auto-exposure
-algorithm's antibanding compensation.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Some kinds of lighting fixtures,<wbr/> such as some fluorescent
-lights,<wbr/> flicker at the rate of the power supply frequency
-(60Hz or 50Hz,<wbr/> depending on country).<wbr/> While this is
-typically not noticeable to a person,<wbr/> it can be visible to
-a camera device.<wbr/> If a camera sets its exposure time to the
-wrong value,<wbr/> the flicker may become visible in the
-viewfinder as flicker or in a final captured image,<wbr/> as a
-set of variable-brightness bands across the image.<wbr/></p>
-<p>Therefore,<wbr/> the auto-exposure routines of camera devices
-include antibanding routines that ensure that the chosen
-exposure value will not cause such banding.<wbr/> The choice of
-exposure time depends on the rate of flicker,<wbr/> which the
-camera device can detect automatically,<wbr/> or the expected
-rate can be selected by the application using this
-control.<wbr/></p>
-<p>A given camera device may not support all of the possible
-options for the antibanding mode.<wbr/> The
-<a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a> key contains
-the available modes for a given camera device.<wbr/></p>
-<p>AUTO mode is the default if it is available on given
-camera device.<wbr/> When AUTO mode is not available,<wbr/> the
-default will be either 50HZ or 60HZ,<wbr/> and both 50HZ
-and 60HZ will be available.<wbr/></p>
-<p>If manual exposure control is enabled (by setting
-<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/>
-then this setting has no effect,<wbr/> and the application must
-ensure it selects exposure times that do not cause banding
-issues.<wbr/> The <a href="#dynamic_android.statistics.sceneFlicker">android.<wbr/>statistics.<wbr/>scene<wbr/>Flicker</a> key can assist
-the application in this.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For all capture request templates,<wbr/> this field must be set
-to AUTO if AUTO mode is available.<wbr/> If AUTO is not available,<wbr/>
-the default must be either 50HZ or 60HZ,<wbr/> and both 50HZ and
-60HZ must be available.<wbr/></p>
-<p>If manual exposure control is enabled (by setting
-<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/>
-then the exposure values provided by the application must not be
-adjusted for antibanding.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.aeExposureCompensation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Adjustment to auto-exposure (AE) target image
-brightness.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Compensation steps
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The adjustment is measured as a count of steps,<wbr/> with the
-step size defined by <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> and the
-allowed range by <a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a>.<wbr/></p>
-<p>For example,<wbr/> if the exposure value (EV) step is 0.<wbr/>333,<wbr/> '6'
-will mean an exposure compensation of +2 EV; -3 will mean an
-exposure compensation of -1 EV.<wbr/> One EV represents a doubling
-of image brightness.<wbr/> Note that this control will only be
-effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF.<wbr/> This control
-will take effect even when <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> <code>== true</code>.<wbr/></p>
-<p>In the event of exposure compensation value being changed,<wbr/> camera device
-may take several frames to reach the newly requested exposure target.<wbr/>
-During that time,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> field will be in the SEARCHING
-state.<wbr/> Once the new exposure target is reached,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> will
-change from SEARCHING to either CONVERGED,<wbr/> LOCKED (if AE lock is enabled),<wbr/> or
-FLASH_<wbr/>REQUIRED (if the scene is too dark for still capture).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.aeLock">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Lock
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Auto-exposure lock is disabled; the AE algorithm
-is free to update its parameters.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>Auto-exposure lock is enabled; the AE algorithm
-must not update the exposure and sensitivity parameters
-while the lock is active.<wbr/></p>
-<p><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> setting changes
-will still take effect while auto-exposure is locked.<wbr/></p>
-<p>Some rare LEGACY devices may not support
-this,<wbr/> in which case the value will always be overridden to OFF.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether auto-exposure (AE) is currently locked to its latest
-calculated values.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to <code>true</code> (ON),<wbr/> the AE algorithm is locked to its latest parameters,<wbr/>
-and will not change exposure settings until the lock is set to <code>false</code> (OFF).<wbr/></p>
-<p>Note that even when AE is locked,<wbr/> the flash may be fired if
-the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>AUTO_<wbr/>FLASH /<wbr/>
-ON_<wbr/>ALWAYS_<wbr/>FLASH /<wbr/> ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE.<wbr/></p>
-<p>When <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> is changed,<wbr/> even if the AE lock
-is ON,<wbr/> the camera device will still adjust its exposure value.<wbr/></p>
-<p>If AE precapture is triggered (see <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>)
-when AE is already locked,<wbr/> the camera device will not change the exposure time
-(<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>) and sensitivity (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>)
-parameters.<wbr/> The flash may be fired if the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>
-is ON_<wbr/>AUTO_<wbr/>FLASH/<wbr/>ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE and the scene is too dark.<wbr/> If the
-<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> the scene may become overexposed.<wbr/>
-Similarly,<wbr/> AE precapture trigger CANCEL has no effect when AE is already locked.<wbr/></p>
-<p>When an AE precapture sequence is triggered,<wbr/> AE unlock will not be able to unlock
-the AE if AE is locked by the camera device internally during precapture metering
-sequence In other words,<wbr/> submitting requests with AE unlock has no effect for an
-ongoing precapture metering sequence.<wbr/> Otherwise,<wbr/> the precapture metering sequence
-will never succeed in a sequence of preview requests where AE lock is always set
-to <code>false</code>.<wbr/></p>
-<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that
-get locked do not necessarily correspond to the settings that were present in the
-latest capture result received from the camera device,<wbr/> since additional captures
-and AE updates may have occurred even before the result was sent out.<wbr/> If an
-application is switching between automatic and manual control and wishes to eliminate
-any flicker during the switch,<wbr/> the following procedure is recommended:</p>
-<ol>
-<li>Starting in auto-AE mode:</li>
-<li>Lock AE</li>
-<li>Wait for the first result to be output that has the AE locked</li>
-<li>Copy exposure settings from that result into a request,<wbr/> set the request to manual AE</li>
-<li>Submit the capture request,<wbr/> proceed to run manual AE as desired.<wbr/></li>
-</ol>
-<p>See <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE lock related state transition details.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.aeMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is disabled.<wbr/></p>
-<p>The application-selected <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
-<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> and
-<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are used by the camera
-device,<wbr/> along with android.<wbr/>flash.<wbr/>* fields,<wbr/> if there's
-a flash unit for this camera device.<wbr/></p>
-<p>Note that auto-white balance (AWB) and auto-focus (AF)
-behavior is device dependent when AE is in OFF mode.<wbr/>
-To have consistent behavior across different devices,<wbr/>
-it is recommended to either set AWB and AF to OFF mode
-or lock AWB and AF before setting AE to OFF.<wbr/>
-See <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a>,<wbr/> and <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>
-for more details.<wbr/></p>
-<p>LEGACY devices do not support the OFF mode and will
-override attempts to use this value to ON.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is active,<wbr/>
-with no flash control.<wbr/></p>
-<p>The application's values for
-<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
-<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and
-<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are ignored.<wbr/> The
-application has control over the various
-android.<wbr/>flash.<wbr/>* fields.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON_AUTO_FLASH</span>
-                    <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls
-the camera's flash unit,<wbr/> firing it in low-light
-conditions.<wbr/></p>
-<p>The flash may be fired during a precapture sequence
-(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and
-may be fired for captures for which the
-<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to
-STILL_<wbr/>CAPTURE</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON_ALWAYS_FLASH</span>
-                    <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls
-the camera's flash unit,<wbr/> always firing it for still
-captures.<wbr/></p>
-<p>The flash may be fired during a precapture sequence
-(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and
-will always be fired for captures for which the
-<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to
-STILL_<wbr/>CAPTURE</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON_AUTO_FLASH_REDEYE</span>
-                    <span class="entry_type_enum_notes"><p>Like ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> but with automatic red eye
-reduction.<wbr/></p>
-<p>If deemed necessary by the camera device,<wbr/> a red eye
-reduction flash will fire during the precapture
-sequence.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired mode for the camera device's
-auto-exposure routine.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.aeAvailableModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is
-AUTO.<wbr/></p>
-<p>When set to any of the ON modes,<wbr/> the camera device's
-auto-exposure routine is enabled,<wbr/> overriding the
-application's selected exposure time,<wbr/> sensor sensitivity,<wbr/>
-and frame duration (<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
-<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and
-<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>).<wbr/> If one of the FLASH modes
-is selected,<wbr/> the camera device's flash unit controls are
-also overridden.<wbr/></p>
-<p>The FLASH modes are only available if the camera device
-has a flash unit (<a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> is <code>true</code>).<wbr/></p>
-<p>If flash TORCH mode is desired,<wbr/> this field must be set to
-ON or OFF,<wbr/> and <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> set to TORCH.<wbr/></p>
-<p>When set to any of the ON modes,<wbr/> the values chosen by the
-camera device auto-exposure routine for the overridden
-fields for a given capture will be available in its
-CaptureResult.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.aeRegions">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>ae<wbr/>Regions
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  5 x area_count
-                </span>
-              <span class="entry_type_visibility"> [public as meteringRectangle]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of metering areas to use for auto-exposure adjustment.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
-            </td>
-
-            <td class="entry_range">
-              <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Not available if <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a> is 0.<wbr/>
-Otherwise will always be present.<wbr/></p>
-<p>The maximum number of regions supported by the device is determined by the value
-of <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a>.<wbr/></p>
-<p>The coordinate system is based on the active pixel array,<wbr/>
-with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
-(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
-bottom-right pixel in the active pixel array.<wbr/></p>
-<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight
-for every pixel in the area.<wbr/> This means that a large metering area
-with the same weight as a smaller area will have more effect in
-the metering result.<wbr/> Metering areas can partially overlap and the
-camera device will add the weights in the overlap region.<wbr/></p>
-<p>The weights are relative to weights of other exposure metering regions,<wbr/> so if only one
-region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0
-weight is ignored.<wbr/></p>
-<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
-camera device.<wbr/></p>
-<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
-capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
-region and output only the intersection rectangle as the metering region in the result
-metadata.<wbr/>  If the region is entirely outside the crop region,<wbr/> it will be ignored and
-not reported in the result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL level representation of MeteringRectangle[] is a
-int[5 * area_<wbr/>count].<wbr/>
-Every five elements represent a metering region of
-(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
-The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
-exclusive on xmax and ymax.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.aeTargetFpsRange">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as rangeInt]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Range over which the auto-exposure routine can
-adjust the capture frame rate to maintain good
-exposure.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Frames per second (FPS)
-            </td>
-
-            <td class="entry_range">
-              <p>Any of the entries in <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Only constrains auto-exposure (AE) algorithm,<wbr/> not
-manual control of <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a> and
-<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.aePrecaptureTrigger">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">IDLE</span>
-                    <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">START</span>
-                    <span class="entry_type_enum_notes"><p>The precapture metering sequence will be started
-by the camera device.<wbr/></p>
-<p>The exact effect of the precapture trigger depends on
-the current AE mode and state.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CANCEL</span>
-                    <span class="entry_type_enum_notes"><p>The camera device will cancel any currently active or completed
-precapture metering sequence,<wbr/> the auto-exposure routine will return to its
-initial state.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether the camera device will trigger a precapture
-metering sequence when it processes this request.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This entry is normally set to IDLE,<wbr/> or is not
-included at all in the request settings.<wbr/> When included and
-set to START,<wbr/> the camera device will trigger the auto-exposure (AE)
-precapture metering sequence.<wbr/></p>
-<p>When set to CANCEL,<wbr/> the camera device will cancel any active
-precapture metering trigger,<wbr/> and return to its initial AE state.<wbr/>
-If a precapture metering sequence is already completed,<wbr/> and the camera
-device has implicitly locked the AE for subsequent still capture,<wbr/> the
-CANCEL trigger will unlock the AE and return to its initial AE state.<wbr/></p>
-<p>The precapture sequence should be triggered before starting a
-high-quality still capture for final metering decisions to
-be made,<wbr/> and for firing pre-capture flash pulses to estimate
-scene brightness and required final capture flash power,<wbr/> when
-the flash is enabled.<wbr/></p>
-<p>Normally,<wbr/> this entry should be set to START for only a
-single request,<wbr/> and the application should wait until the
-sequence completes before starting a new one.<wbr/></p>
-<p>When a precapture metering sequence is finished,<wbr/> the camera device
-may lock the auto-exposure routine internally to be able to accurately expose the
-subsequent still capture image (<code><a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE</code>).<wbr/>
-For this case,<wbr/> the AE may not resume normal scan if no subsequent still capture is
-submitted.<wbr/> To ensure that the AE routine restarts normal scan,<wbr/> the application should
-submit a request with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == true</code>,<wbr/> followed by a request
-with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == false</code>,<wbr/> if the application decides not to submit a
-still capture request after the precapture sequence completes.<wbr/> Alternatively,<wbr/> for
-API level 23 or newer devices,<wbr/> the CANCEL can be used to unlock the camera device
-internally locked AE if the application doesn't submit a still capture request after
-the AE precapture trigger.<wbr/> Note that,<wbr/> the CANCEL was added in API level 23,<wbr/> and must not
-be used in devices that have earlier API levels.<wbr/></p>
-<p>The exact effect of auto-exposure (AE) precapture trigger
-depends on the current AE mode and state; see
-<a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE precapture state transition
-details.<wbr/></p>
-<p>On LEGACY-level devices,<wbr/> the precapture trigger is not supported;
-capturing a high-resolution JPEG image will automatically trigger a
-precapture sequence before the high-resolution capture,<wbr/> including
-potentially firing a pre-capture flash.<wbr/></p>
-<p>Using the precapture trigger and the auto-focus trigger <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>
-simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between
-the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a
-focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous
-trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and
-changes to <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> indicating the start of the precapture sequence,<wbr/> for
-example.<wbr/></p>
-<p>If both the precapture and the auto-focus trigger are activated on the same request,<wbr/> then
-the camera device will complete them in the optimal order for that device.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL must support triggering the AE precapture trigger while an AF trigger is active
-(and vice versa),<wbr/> or at the same time as the AF trigger.<wbr/>  It is acceptable for the HAL to
-treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the
-AE trigger.<wbr/>  Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/>
-to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.afMode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>af<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>The auto-focus routine does not control the lens;
-<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> is controlled by the
-application.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">AUTO</span>
-                    <span class="entry_type_enum_notes"><p>Basic automatic focus mode.<wbr/></p>
-<p>In this mode,<wbr/> the lens does not move unless
-the autofocus trigger action is called.<wbr/> When that trigger
-is activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to
-the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/></p>
-<p>Always supported if lens is not fixed focus.<wbr/></p>
-<p>Use <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> to determine if lens
-is fixed-focus.<wbr/></p>
-<p>Triggering AF_<wbr/>CANCEL resets the lens position to default,<wbr/>
-and sets the AF state to INACTIVE.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MACRO</span>
-                    <span class="entry_type_enum_notes"><p>Close-up focusing mode.<wbr/></p>
-<p>In this mode,<wbr/> the lens does not move unless the
-autofocus trigger action is called.<wbr/> When that trigger is
-activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to
-the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/> This
-mode is optimized for focusing on objects very close to
-the camera.<wbr/></p>
-<p>When that trigger is activated,<wbr/> AF will transition to
-ACTIVE_<wbr/>SCAN,<wbr/> then to the outcome of the scan (FOCUSED or
-NOT_<wbr/>FOCUSED).<wbr/> Triggering cancel AF resets the lens
-position to default,<wbr/> and sets the AF state to
-INACTIVE.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CONTINUOUS_VIDEO</span>
-                    <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens
-position continually to attempt to provide a
-constantly-in-focus image stream.<wbr/></p>
-<p>The focusing behavior should be suitable for good quality
-video recording; typically this means slower focus
-movement and no overshoots.<wbr/> When the AF trigger is not
-involved,<wbr/> the AF algorithm should start in INACTIVE state,<wbr/>
-and then transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED
-states as appropriate.<wbr/> When the AF trigger is activated,<wbr/>
-the algorithm should immediately transition into
-AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the
-lens position until a cancel AF trigger is received.<wbr/></p>
-<p>Once cancel is received,<wbr/> the algorithm should transition
-back to INACTIVE and resume passive scan.<wbr/> Note that this
-behavior is not identical to CONTINUOUS_<wbr/>PICTURE,<wbr/> since an
-ongoing PASSIVE_<wbr/>SCAN must immediately be
-canceled.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CONTINUOUS_PICTURE</span>
-                    <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens
-position continually to attempt to provide a
-constantly-in-focus image stream.<wbr/></p>
-<p>The focusing behavior should be suitable for still image
-capture; typically this means focusing as fast as
-possible.<wbr/> When the AF trigger is not involved,<wbr/> the AF
-algorithm should start in INACTIVE state,<wbr/> and then
-transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED states as
-appropriate as it attempts to maintain focus.<wbr/> When the AF
-trigger is activated,<wbr/> the algorithm should finish its
-PASSIVE_<wbr/>SCAN if active,<wbr/> and then transition into
-AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the
-lens position until a cancel AF trigger is received.<wbr/></p>
-<p>When the AF cancel trigger is activated,<wbr/> the algorithm
-should transition back to INACTIVE and then act as if it
-has just been started.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">EDOF</span>
-                    <span class="entry_type_enum_notes"><p>Extended depth of field (digital focus) mode.<wbr/></p>
-<p>The camera device will produce images with an extended
-depth of field automatically; no special focusing
-operations need to be done before taking a picture.<wbr/></p>
-<p>AF triggers are ignored,<wbr/> and the AF state will always be
-INACTIVE.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether auto-focus (AF) is currently enabled,<wbr/> and what
-mode it is set to.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.afAvailableModes">android.<wbr/>control.<wbr/>af<wbr/>Available<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> = AUTO and the lens is not fixed focus
-(i.<wbr/>e.<wbr/> <code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> &gt; 0</code>).<wbr/> Also note that
-when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/> the behavior of AF is device
-dependent.<wbr/> It is recommended to lock AF by using <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> before
-setting <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> to OFF,<wbr/> or set AF mode to OFF when AE is OFF.<wbr/></p>
-<p>If the lens is controlled by the camera device auto-focus algorithm,<wbr/>
-the camera device will report the current AF status in <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a>
-in result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When afMode is AUTO or MACRO,<wbr/> the lens must not move until an AF trigger is sent in a
-request (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> <code>==</code> START).<wbr/> After an AF trigger,<wbr/> the afState will end
-up with either FOCUSED_<wbr/>LOCKED or NOT_<wbr/>FOCUSED_<wbr/>LOCKED state (see
-<a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> which indicates that the lens is
-locked and will not move.<wbr/> If camera movement (e.<wbr/>g.<wbr/> tilting camera) causes the lens to move
-after the lens is locked,<wbr/> the HAL must compensate this movement appropriately such that
-the same focal plane remains in focus.<wbr/></p>
-<p>When afMode is one of the continuous auto focus modes,<wbr/> the HAL is free to start a AF
-scan whenever it's not locked.<wbr/> When the lens is locked after an AF trigger
-(see <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> the HAL should maintain the
-same lock behavior as above.<wbr/></p>
-<p>When afMode is OFF,<wbr/> the application controls focus manually.<wbr/> The accuracy of the
-focus distance control depends on the <a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a>.<wbr/>
-However,<wbr/> the lens must not move regardless of the camera movement for any focus distance
-manual control.<wbr/></p>
-<p>To put this in concrete terms,<wbr/> if the camera has lens elements which may move based on
-camera orientation or motion (e.<wbr/>g.<wbr/> due to gravity),<wbr/> then the HAL must drive the lens to
-remain in a fixed position invariant to the camera's orientation or motion,<wbr/> for example,<wbr/>
-by using accelerometer measurements in the lens control logic.<wbr/> This is a typical issue
-that will arise on camera modules with open-loop VCMs.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.afRegions">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>af<wbr/>Regions
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  5 x area_count
-                </span>
-              <span class="entry_type_visibility"> [public as meteringRectangle]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of metering areas to use for auto-focus.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
-            </td>
-
-            <td class="entry_range">
-              <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Not available if <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a> is 0.<wbr/>
-Otherwise will always be present.<wbr/></p>
-<p>The maximum number of focus areas supported by the device is determined by the value
-of <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a>.<wbr/></p>
-<p>The coordinate system is based on the active pixel array,<wbr/>
-with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
-(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
-bottom-right pixel in the active pixel array.<wbr/></p>
-<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight
-for every pixel in the area.<wbr/> This means that a large metering area
-with the same weight as a smaller area will have more effect in
-the metering result.<wbr/> Metering areas can partially overlap and the
-camera device will add the weights in the overlap region.<wbr/></p>
-<p>The weights are relative to weights of other metering regions,<wbr/> so if only one region
-is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0 weight is
-ignored.<wbr/></p>
-<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
-camera device.<wbr/></p>
-<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
-capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
-region and output only the intersection rectangle as the metering region in the result
-metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and
-not reported in the result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL level representation of MeteringRectangle[] is a
-int[5 * area_<wbr/>count].<wbr/>
-Every five elements represent a metering region of
-(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
-The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
-exclusive on xmax and ymax.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.afTrigger">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>af<wbr/>Trigger
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">IDLE</span>
-                    <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">START</span>
-                    <span class="entry_type_enum_notes"><p>Autofocus will trigger now.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CANCEL</span>
-                    <span class="entry_type_enum_notes"><p>Autofocus will return to its initial
-state,<wbr/> and cancel any currently active trigger.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether the camera device will trigger autofocus for this request.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This entry is normally set to IDLE,<wbr/> or is not
-included at all in the request settings.<wbr/></p>
-<p>When included and set to START,<wbr/> the camera device will trigger the
-autofocus algorithm.<wbr/> If autofocus is disabled,<wbr/> this trigger has no effect.<wbr/></p>
-<p>When set to CANCEL,<wbr/> the camera device will cancel any active trigger,<wbr/>
-and return to its initial AF state.<wbr/></p>
-<p>Generally,<wbr/> applications should set this entry to START or CANCEL for only a
-single capture,<wbr/> and then return it to IDLE (or not set at all).<wbr/> Specifying
-START for multiple captures in a row means restarting the AF operation over
-and over again.<wbr/></p>
-<p>See <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for what the trigger means for each AF mode.<wbr/></p>
-<p>Using the autofocus trigger and the precapture trigger <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>
-simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between
-the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a
-focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous
-trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and
-changes to <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a>,<wbr/> for example.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL must support triggering the AF trigger while an AE precapture trigger is active
-(and vice versa),<wbr/> or at the same time as the AE trigger.<wbr/>  It is acceptable for the HAL to
-treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the
-AE trigger.<wbr/>  Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/>
-to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.awbLock">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>awb<wbr/>Lock
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Auto-white balance lock is disabled; the AWB
-algorithm is free to update its parameters if in AUTO
-mode.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>Auto-white balance lock is enabled; the AWB
-algorithm will not update its parameters while the lock
-is active.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether auto-white balance (AWB) is currently locked to its
-latest calculated values.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to <code>true</code> (ON),<wbr/> the AWB algorithm is locked to its latest parameters,<wbr/>
-and will not change color balance settings until the lock is set to <code>false</code> (OFF).<wbr/></p>
-<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that
-get locked do not necessarily correspond to the settings that were present in the
-latest capture result received from the camera device,<wbr/> since additional captures
-and AWB updates may have occurred even before the result was sent out.<wbr/> If an
-application is switching between automatic and manual control and wishes to eliminate
-any flicker during the switch,<wbr/> the following procedure is recommended:</p>
-<ol>
-<li>Starting in auto-AWB mode:</li>
-<li>Lock AWB</li>
-<li>Wait for the first result to be output that has the AWB locked</li>
-<li>Copy AWB settings from that result into a request,<wbr/> set the request to manual AWB</li>
-<li>Submit the capture request,<wbr/> proceed to run manual AWB as desired.<wbr/></li>
-</ol>
-<p>Note that AWB lock is only meaningful when
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> is in the AUTO mode; in other modes,<wbr/>
-AWB is already fixed to a specific setting.<wbr/></p>
-<p>Some LEGACY devices may not support ON; the value is then overridden to OFF.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.awbMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>awb<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled.<wbr/></p>
-<p>The application-selected color transform matrix
-(<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>) and gains
-(<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>) are used by the camera
-device for manual white balance control.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">AUTO</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is active.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">INCANDESCENT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses incandescent light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>While the exact white balance transforms are up to the
-camera device,<wbr/> they will approximately match the CIE
-standard illuminant A.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FLUORESCENT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses fluorescent light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>While the exact white balance transforms are up to the
-camera device,<wbr/> they will approximately match the CIE
-standard illuminant F2.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">WARM_FLUORESCENT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses warm fluorescent light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>While the exact white balance transforms are up to the
-camera device,<wbr/> they will approximately match the CIE
-standard illuminant F4.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">DAYLIGHT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses daylight light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>While the exact white balance transforms are up to the
-camera device,<wbr/> they will approximately match the CIE
-standard illuminant D65.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CLOUDY_DAYLIGHT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses cloudy daylight light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">TWILIGHT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses twilight light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SHADE</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses shade light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether auto-white balance (AWB) is currently setting the color
-transform fields,<wbr/> and what its illumination target
-is.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.awbAvailableModes">android.<wbr/>control.<wbr/>awb<wbr/>Available<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is AUTO.<wbr/></p>
-<p>When set to the ON mode,<wbr/> the camera device's auto-white balance
-routine is enabled,<wbr/> overriding the application's selected
-<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
-<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/> Note that when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>
-is OFF,<wbr/> the behavior of AWB is device dependent.<wbr/> It is recommened to
-also set AWB mode to OFF or lock AWB by using <a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> before
-setting AE mode to OFF.<wbr/></p>
-<p>When set to the OFF mode,<wbr/> the camera device's auto-white balance
-routine is disabled.<wbr/> The application manually controls the white
-balance by <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>
-and <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/></p>
-<p>When set to any other modes,<wbr/> the camera device's auto-white
-balance routine is disabled.<wbr/> The camera device uses each
-particular illumination target for white balance
-adjustment.<wbr/> The application's values for
-<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/>
-<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
-<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> are ignored.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.awbRegions">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>awb<wbr/>Regions
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  5 x area_count
-                </span>
-              <span class="entry_type_visibility"> [public as meteringRectangle]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of metering areas to use for auto-white-balance illuminant
-estimation.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
-            </td>
-
-            <td class="entry_range">
-              <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Not available if <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a> is 0.<wbr/>
-Otherwise will always be present.<wbr/></p>
-<p>The maximum number of regions supported by the device is determined by the value
-of <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a>.<wbr/></p>
-<p>The coordinate system is based on the active pixel array,<wbr/>
-with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
-(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
-bottom-right pixel in the active pixel array.<wbr/></p>
-<p>The weight must range from 0 to 1000,<wbr/> and represents a weight
-for every pixel in the area.<wbr/> This means that a large metering area
-with the same weight as a smaller area will have more effect in
-the metering result.<wbr/> Metering areas can partially overlap and the
-camera device will add the weights in the overlap region.<wbr/></p>
-<p>The weights are relative to weights of other white balance metering regions,<wbr/> so if
-only one region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with
-0 weight is ignored.<wbr/></p>
-<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
-camera device.<wbr/></p>
-<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
-capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
-region and output only the intersection rectangle as the metering region in the result
-metadata.<wbr/>  If the region is entirely outside the crop region,<wbr/> it will be ignored and
-not reported in the result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL level representation of MeteringRectangle[] is a
-int[5 * area_<wbr/>count].<wbr/>
-Every five elements represent a metering region of
-(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
-The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
-exclusive on xmax and ymax.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.captureIntent">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>capture<wbr/>Intent
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">CUSTOM</span>
-                    <span class="entry_type_enum_notes"><p>The goal of this request doesn't fall into the other
-categories.<wbr/> The camera device will default to preview-like
-behavior.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PREVIEW</span>
-                    <span class="entry_type_enum_notes"><p>This request is for a preview-like use case.<wbr/></p>
-<p>The precapture trigger may be used to start off a metering
-w/<wbr/>flash sequence.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">STILL_CAPTURE</span>
-                    <span class="entry_type_enum_notes"><p>This request is for a still capture-type
-use case.<wbr/></p>
-<p>If the flash unit is under automatic control,<wbr/> it may fire as needed.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">VIDEO_RECORD</span>
-                    <span class="entry_type_enum_notes"><p>This request is for a video recording
-use case.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">VIDEO_SNAPSHOT</span>
-                    <span class="entry_type_enum_notes"><p>This request is for a video snapshot (still
-image while recording video) use case.<wbr/></p>
-<p>The camera device should take the highest-quality image
-possible (given the other settings) without disrupting the
-frame rate of video recording.<wbr/>  </p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
-                    <span class="entry_type_enum_notes"><p>This request is for a ZSL usecase; the
-application will stream full-resolution images and
-reprocess one or several later for a final
-capture.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MANUAL</span>
-                    <span class="entry_type_enum_notes"><p>This request is for manual capture use case where
-the applications want to directly control the capture parameters.<wbr/></p>
-<p>For example,<wbr/> the application may wish to manually control
-<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> etc.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Information to the camera device 3A (auto-exposure,<wbr/>
-auto-focus,<wbr/> auto-white balance) routines about the purpose
-of this capture,<wbr/> to help the camera device to decide optimal 3A
-strategy.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control (except for MANUAL) is only effective if
-<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> != OFF</code> and any 3A routine is active.<wbr/></p>
-<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG will be supported if <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>
-contains PRIVATE_<wbr/>REPROCESSING or YUV_<wbr/>REPROCESSING.<wbr/> MANUAL will be supported if
-<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains MANUAL_<wbr/>SENSOR.<wbr/> Other intent values are
-always supported.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.effectMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>effect<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No color effect will be applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MONO</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "monocolor" effect where the image is mapped into
-a single color.<wbr/></p>
-<p>This will typically be grayscale.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">NEGATIVE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "photo-negative" effect where the image's colors
-are inverted.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SOLARIZE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "solarisation" effect (Sabattier effect) where the
-image is wholly or partially reversed in
-tone.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SEPIA</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "sepia" effect where the image is mapped into warm
-gray,<wbr/> red,<wbr/> and brown tones.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">POSTERIZE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "posterization" effect where the image uses
-discrete regions of tone rather than a continuous
-gradient of tones.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">WHITEBOARD</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "whiteboard" effect where the image is typically displayed
-as regions of white,<wbr/> with black or grey details.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">BLACKBOARD</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "blackboard" effect where the image is typically displayed
-as regions of black,<wbr/> with white or grey details.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">AQUA</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>An "aqua" effect where a blue hue is added to the image.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A special color effect to apply.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.availableEffects">android.<wbr/>control.<wbr/>available<wbr/>Effects</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When this mode is set,<wbr/> a color effect will be applied
-to images produced by the camera device.<wbr/> The interpretation
-and implementation of these color effects is left to the
-implementor of the camera device,<wbr/> and should not be
-depended on to be consistent (or present) across all
-devices.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.mode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Full application control of pipeline.<wbr/></p>
-<p>All control by the device's metering and focusing (3A)
-routines is disabled,<wbr/> and no other settings in
-android.<wbr/>control.<wbr/>* have any effect,<wbr/> except that
-<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> may be used by the camera
-device to select post-processing values for processing
-blocks that do not allow for manual control,<wbr/> or are not
-exposed by the camera API.<wbr/></p>
-<p>However,<wbr/> the camera device's 3A routines may continue to
-collect statistics and update their internal state so that
-when control is switched to AUTO mode,<wbr/> good control values
-can be immediately applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">AUTO</span>
-                    <span class="entry_type_enum_notes"><p>Use settings for each individual 3A routine.<wbr/></p>
-<p>Manual control of capture parameters is disabled.<wbr/> All
-controls in android.<wbr/>control.<wbr/>* besides sceneMode take
-effect.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">USE_SCENE_MODE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Use a specific scene mode.<wbr/></p>
-<p>Enabling this disables control.<wbr/>aeMode,<wbr/> control.<wbr/>awbMode and
-control.<wbr/>afMode controls; the camera device will ignore
-those settings while USE_<wbr/>SCENE_<wbr/>MODE is active (except for
-FACE_<wbr/>PRIORITY scene mode).<wbr/> Other control entries are still active.<wbr/>
-This setting can only be used if scene mode is supported (i.<wbr/>e.<wbr/>
-<a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a>
-contain some modes other than DISABLED).<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">OFF_KEEP_STATE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Same as OFF mode,<wbr/> except that this capture will not be
-used by camera device background auto-exposure,<wbr/> auto-white balance and
-auto-focus algorithms (3A) to update their statistics.<wbr/></p>
-<p>Specifically,<wbr/> the 3A routines are locked to the last
-values set from a request with AUTO,<wbr/> OFF,<wbr/> or
-USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> and any statistics or state updates
-collected from manual captures with OFF_<wbr/>KEEP_<wbr/>STATE will be
-discarded by the camera device.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Overall mode of 3A (auto-exposure,<wbr/> auto-white-balance,<wbr/> auto-focus) control
-routines.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.availableModes">android.<wbr/>control.<wbr/>available<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is a top-level 3A control switch.<wbr/> When set to OFF,<wbr/> all 3A control
-by the camera device is disabled.<wbr/> The application must set the fields for
-capture parameters itself.<wbr/></p>
-<p>When set to AUTO,<wbr/> the individual algorithm controls in
-android.<wbr/>control.<wbr/>* are in effect,<wbr/> such as <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>.<wbr/></p>
-<p>When set to USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> the individual controls in
-android.<wbr/>control.<wbr/>* are mostly disabled,<wbr/> and the camera device implements
-one of the scene mode settings (such as ACTION,<wbr/> SUNSET,<wbr/> or PARTY)
-as it wishes.<wbr/> The camera device scene mode 3A settings are provided by
-<a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">capture results</a>.<wbr/></p>
-<p>When set to OFF_<wbr/>KEEP_<wbr/>STATE,<wbr/> it is similar to OFF mode,<wbr/> the only difference
-is that this frame will not be used by camera device background 3A statistics
-update,<wbr/> as if this frame is never captured.<wbr/> This mode can be used in the scenario
-where the application doesn't want a 3A manual control capture to affect
-the subsequent auto 3A capture results.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.sceneMode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>scene<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">DISABLED</span>
-                    <span class="entry_type_enum_value">0</span>
-                    <span class="entry_type_enum_notes"><p>Indicates that no scene modes are set for a given capture request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FACE_PRIORITY</span>
-                    <span class="entry_type_enum_notes"><p>If face detection support exists,<wbr/> use face
-detection data for auto-focus,<wbr/> auto-white balance,<wbr/> and
-auto-exposure routines.<wbr/></p>
-<p>If face detection statistics are disabled
-(i.<wbr/>e.<wbr/> <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> is set to OFF),<wbr/>
-this should still operate correctly (but will not return
-face detection statistics to the framework).<wbr/></p>
-<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
-remain active when FACE_<wbr/>PRIORITY is set.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ACTION</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving objects.<wbr/></p>
-<p>Similar to SPORTS.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PORTRAIT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for still photos of people.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">LANDSCAPE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for photos of distant macroscopic objects.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">NIGHT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for low-light settings.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">NIGHT_PORTRAIT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for still photos of people in low-light
-settings.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">THEATRE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings where flash must
-remain off.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">BEACH</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor beach settings.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SNOW</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor settings containing snow.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SUNSET</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for scenes of the setting sun.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">STEADYPHOTO</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized to avoid blurry photos due to small amounts of
-device motion (for example: due to hand shake).<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FIREWORKS</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for nighttime photos of fireworks.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SPORTS</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving people.<wbr/></p>
-<p>Similar to ACTION.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PARTY</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings with multiple moving
-people.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CANDLELIGHT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for dim settings where the main light source
-is a flame.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">BARCODE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for accurately capturing a photo of barcode
-for use by camera applications that wish to read the
-barcode value.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_SPEED_VIDEO</span>
-                    <span class="entry_type_enum_deprecated">[deprecated]</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>This is deprecated,<wbr/> please use <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>
-and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a>
-for high speed video recording.<wbr/></p>
-<p>Optimized for high speed video recording (frame rate &gt;=60fps) use case.<wbr/></p>
-<p>The supported high speed video sizes and fps ranges are specified in
-<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> To get desired
-output frame rates,<wbr/> the application is only allowed to select video size
-and fps range combinations listed in this static metadata.<wbr/> The fps range
-can be control via <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a>.<wbr/></p>
-<p>In this mode,<wbr/> the camera device will override aeMode,<wbr/> awbMode,<wbr/> and afMode to
-ON,<wbr/> ON,<wbr/> and CONTINUOUS_<wbr/>VIDEO,<wbr/> respectively.<wbr/> All post-processing block mode
-controls will be overridden to be FAST.<wbr/> Therefore,<wbr/> no manual control of capture
-and post-processing parameters is possible.<wbr/> All other controls operate the
-same as when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == AUTO.<wbr/> This means that all other
-android.<wbr/>control.<wbr/>* fields continue to work,<wbr/> such as</p>
-<ul>
-<li><a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a></li>
-<li><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a></li>
-<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li>
-<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li>
-<li><a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></li>
-<li><a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a></li>
-<li><a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a></li>
-<li><a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a></li>
-<li><a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a></li>
-<li><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a></li>
-</ul>
-<p>Outside of android.<wbr/>control.<wbr/>*,<wbr/> the following controls will work:</p>
-<ul>
-<li><a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> (automatic flash for still capture will not work since aeMode is ON)</li>
-<li><a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> (if it is supported)</li>
-<li><a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a></li>
-<li><a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a></li>
-</ul>
-<p>For high speed recording use case,<wbr/> the actual maximum supported frame rate may
-be lower than what camera can output,<wbr/> depending on the destination Surfaces for
-the image data.<wbr/> For example,<wbr/> if the destination surface is from video encoder,<wbr/>
-the application need check if the video encoder is capable of supporting the
-high frame rate for a given video size,<wbr/> or it will end up with lower recording
-frame rate.<wbr/> If the destination surface is from preview window,<wbr/> the preview frame
-rate will be bounded by the screen refresh rate.<wbr/></p>
-<p>The camera device will only support up to 2 output high speed streams
-(processed non-stalling format defined in <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>)
-in this mode.<wbr/> This control will be effective only if all of below conditions are true:</p>
-<ul>
-<li>The application created no more than maxNumHighSpeedStreams processed non-stalling
-format output streams,<wbr/> where maxNumHighSpeedStreams is calculated as
-min(2,<wbr/> <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>[Processed (but not-stalling)]).<wbr/></li>
-<li>The stream sizes are selected from the sizes reported by
-<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/></li>
-<li>No processed non-stalling or raw streams are configured.<wbr/></li>
-</ul>
-<p>When above conditions are NOT satistied,<wbr/> the controls of this mode and
-<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> will be ignored by the camera device,<wbr/>
-the camera device will fall back to <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> <code>==</code> AUTO,<wbr/>
-and the returned capture result metadata will give the fps range choosen
-by the camera device.<wbr/></p>
-<p>Switching into or out of this mode may trigger some camera ISP/<wbr/>sensor
-reconfigurations,<wbr/> which may introduce extra latency.<wbr/> It is recommended that
-the application avoids unnecessary scene mode switch as much as possible.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HDR</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Turn on a device-specific high dynamic range (HDR) mode.<wbr/></p>
-<p>In this scene mode,<wbr/> the camera device captures images
-that keep a larger range of scene illumination levels
-visible in the final image.<wbr/> For example,<wbr/> when taking a
-picture of a object in front of a bright window,<wbr/> both
-the object and the scene through the window may be
-visible when using HDR mode,<wbr/> while in normal AUTO mode,<wbr/>
-one or the other may be poorly exposed.<wbr/> As a tradeoff,<wbr/>
-HDR mode generally takes much longer to capture a single
-image,<wbr/> has no user control,<wbr/> and may have other artifacts
-depending on the HDR method used.<wbr/></p>
-<p>Therefore,<wbr/> HDR captures operate at a much slower rate
-than regular captures.<wbr/></p>
-<p>In this mode,<wbr/> on LIMITED or FULL devices,<wbr/> when a request
-is made with a <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> of
-STILL_<wbr/>CAPTURE,<wbr/> the camera device will capture an image
-using a high dynamic range capture technique.<wbr/>  On LEGACY
-devices,<wbr/> captures that target a JPEG-format output will
-be captured with HDR,<wbr/> and the capture intent is not
-relevant.<wbr/></p>
-<p>The HDR capture may involve the device capturing a burst
-of images internally and combining them into one,<wbr/> or it
-may involve the device using specialized high dynamic
-range capture hardware.<wbr/> In all cases,<wbr/> a single image is
-produced in response to a capture request submitted
-while in HDR mode.<wbr/></p>
-<p>Since substantial post-processing is generally needed to
-produce an HDR image,<wbr/> only YUV,<wbr/> PRIVATE,<wbr/> and JPEG
-outputs are supported for LIMITED/<wbr/>FULL device HDR
-captures,<wbr/> and only JPEG outputs are supported for LEGACY
-HDR captures.<wbr/> Using a RAW output for HDR capture is not
-supported.<wbr/></p>
-<p>Some devices may also support always-on HDR,<wbr/> which
-applies HDR processing at full frame rate.<wbr/>  For these
-devices,<wbr/> intents other than STILL_<wbr/>CAPTURE will also
-produce an HDR output with no frame rate impact compared
-to normal operation,<wbr/> though the quality may be lower
-than for STILL_<wbr/>CAPTURE intents.<wbr/></p>
-<p>If SCENE_<wbr/>MODE_<wbr/>HDR is used with unsupported output types
-or capture intents,<wbr/> the images captured will be as if
-the SCENE_<wbr/>MODE was not enabled at all.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FACE_PRIORITY_LOW_LIGHT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_hidden">[hidden]</span>
-                    <span class="entry_type_enum_notes"><p>Same as FACE_<wbr/>PRIORITY scene mode,<wbr/> except that the camera
-device will choose higher sensitivity values (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>)
-under low light conditions.<wbr/></p>
-<p>The camera device may be tuned to expose the images in a reduced
-sensitivity range to produce the best quality images.<wbr/> For example,<wbr/>
-if the <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> gives range of [100,<wbr/> 1600],<wbr/>
-the camera device auto-exposure routine tuning process may limit the actual
-exposure sensitivity range to [100,<wbr/> 1200] to ensure that the noise level isn't
-exessive in order to preserve the image quality.<wbr/> Under this situation,<wbr/> the image under
-low light may be under-exposed when the sensor max exposure time (bounded by the
-<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of the
-ON_<wbr/>* modes) and effective max sensitivity are reached.<wbr/> This scene mode allows the
-camera device auto-exposure routine to increase the sensitivity up to the max
-sensitivity specified by <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> when the scene is too
-dark and the max exposure time is reached.<wbr/> The captured images may be noisier
-compared with the images captured in normal FACE_<wbr/>PRIORITY mode; therefore,<wbr/> it is
-recommended that the application only use this scene mode when it is capable of
-reducing the noise level of the captured images.<wbr/></p>
-<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
-remain active when FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT is set.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">DEVICE_CUSTOM_START</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_hidden">[hidden]</span>
-                    <span class="entry_type_enum_value">100</span>
-                    <span class="entry_type_enum_notes"><p>Scene mode values within the range of
-<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific
-customized scene modes.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">DEVICE_CUSTOM_END</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_hidden">[hidden]</span>
-                    <span class="entry_type_enum_value">127</span>
-                    <span class="entry_type_enum_notes"><p>Scene mode values within the range of
-<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific
-customized scene modes.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Control for which scene mode is currently active.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Scene modes are custom camera modes optimized for a certain set of conditions and
-capture settings.<wbr/></p>
-<p>This is the mode that that is active when
-<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code>.<wbr/> Aside from FACE_<wbr/>PRIORITY,<wbr/> these modes will
-disable <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
-while in use.<wbr/></p>
-<p>The interpretation and implementation of these scene modes is left
-to the implementor of the camera device.<wbr/> Their behavior will not be
-consistent across all devices,<wbr/> and any given device may only implement
-a subset of these modes.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL implementations that include scene modes are expected to provide
-the per-scene settings to use for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> in
-<a href="#static_android.control.sceneModeOverrides">android.<wbr/>control.<wbr/>scene<wbr/>Mode<wbr/>Overrides</a>.<wbr/></p>
-<p>For HIGH_<wbr/>SPEED_<wbr/>VIDEO mode,<wbr/> if it is included in <a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a>,<wbr/>
-the HAL must list supported video size and fps range in
-<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> For a given size,<wbr/> e.<wbr/>g.<wbr/>
-1280x720,<wbr/> if the HAL has two different sensor configurations for normal streaming
-mode and high speed streaming,<wbr/> when this scene mode is set/<wbr/>reset in a sequence of capture
-requests,<wbr/> the HAL may have to switch between different sensor modes.<wbr/>
-This mode is deprecated in HAL3.<wbr/>3,<wbr/> to support high speed video recording,<wbr/> please implement
-<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a> and CONSTRAINED_<wbr/>HIGH_<wbr/>SPEED_<wbr/>VIDEO
-capbility defined in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.videoStabilizationMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Video stabilization is disabled.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>Video stabilization is enabled.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether video stabilization is
-active.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Video stabilization automatically warps images from
-the camera in order to stabilize motion between consecutive frames.<wbr/></p>
-<p>If enabled,<wbr/> video stabilization can modify the
-<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> to keep the video stream stabilized.<wbr/></p>
-<p>Switching between different video stabilization modes may take several
-frames to initialize,<wbr/> the camera device will report the current mode
-in capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/>
-the video stabilization modes in the first several capture results may
-still be "OFF",<wbr/> and it will become "ON" when the initialization is
-done.<wbr/></p>
-<p>In addition,<wbr/> not all recording sizes or frame rates may be supported for
-stabilization by a device that reports stabilization support.<wbr/> It is guaranteed
-that an output targeting a MediaRecorder or MediaCodec will be stabilized if
-the recording resolution is less than or equal to 1920 x 1080 (width less than
-or equal to 1920,<wbr/> height less than or equal to 1080),<wbr/> and the recording
-frame rate is less than or equal to 30fps.<wbr/>  At other sizes,<wbr/> the CaptureResult
-<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a> field will return
-OFF if the recording output is not stabilized,<wbr/> or if there are no output
-Surface types that can be stabilized.<wbr/></p>
-<p>If a camera device supports both this mode and OIS
-(<a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may
-produce undesirable interaction,<wbr/> so it is recommended not to enable
-both at the same time.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.control.postRawSensitivityBoost">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The amount of additional sensitivity boost applied to output images
-after RAW sensor data is captured.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              ISO arithmetic units,<wbr/> the same as android.<wbr/>sensor.<wbr/>sensitivity
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.postRawSensitivityBoostRange">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost<wbr/>Range</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Some camera devices support additional digital sensitivity boosting in the
-camera processing pipeline after sensor RAW image is captured.<wbr/>
-Such a boost will be applied to YUV/<wbr/>JPEG format output images but will not
-have effect on RAW output formats like RAW_<wbr/>SENSOR,<wbr/> RAW10,<wbr/> RAW12 or RAW_<wbr/>OPAQUE.<wbr/></p>
-<p>This key will be <code>null</code> for devices that do not support any RAW format
-outputs.<wbr/> For devices that do support RAW format outputs,<wbr/> this key will always
-present,<wbr/> and if a device does not support post RAW sensitivity boost,<wbr/> it will
-list <code>100</code> in this key.<wbr/></p>
-<p>If the camera device cannot apply the exact boost requested,<wbr/> it will reduce the
-boost to the nearest supported value.<wbr/>
-The final boost value used will be available in the output capture result.<wbr/></p>
-<p>For devices that support post RAW sensitivity boost,<wbr/> the YUV/<wbr/>JPEG output images
-of such device will have the total sensitivity of
-<code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> * <a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> /<wbr/> 100</code>
-The sensitivity of RAW format images will always be <code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></code></p>
-<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
-OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.control.aeAvailableAntibandingModes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of auto-exposure antibanding modes for <a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> that are
-supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Not all of the auto-exposure anti-banding modes may be
-supported by a given camera device.<wbr/> This field lists the
-valid anti-banding modes that the application may request
-for this camera device with the
-<a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> control.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.aeAvailableModes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of auto-exposure modes for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> that are supported by this camera
-device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Not all the auto-exposure modes may be supported by a
-given camera device,<wbr/> especially if no flash unit is
-available.<wbr/> This entry lists the valid modes for
-<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> for this camera device.<wbr/></p>
-<p>All camera devices support ON,<wbr/> and all camera devices with flash
-units support ON_<wbr/>AUTO_<wbr/>FLASH and ON_<wbr/>ALWAYS_<wbr/>FLASH.<wbr/></p>
-<p>FULL mode camera devices always support OFF mode,<wbr/>
-which enables application control of camera exposure time,<wbr/>
-sensitivity,<wbr/> and frame duration.<wbr/></p>
-<p>LEGACY mode camera devices never support OFF mode.<wbr/>
-LIMITED mode devices support OFF if they support the MANUAL_<wbr/>SENSOR
-capability.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.aeAvailableTargetFpsRanges">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2 x n
-                </span>
-              <span class="entry_type_visibility"> [public as rangeInt]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">list of pairs of frame rates</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of frame rate ranges for <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> supported by
-this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Frames per second (FPS)
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For devices at the LEGACY level or above:</p>
-<ul>
-<li>
-<p>For constant-framerate recording,<wbr/> for each normal
-<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a>,<wbr/> that is,<wbr/> a
-<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a> that has
-<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#quality">quality</a> in
-the range [<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#QUALITY_LOW">QUALITY_<wbr/>LOW</a>,<wbr/>
-<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#QUALITY_2160P">QUALITY_<wbr/>2160P</a>],<wbr/> if the profile is
-supported by the device and has
-<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#videoFrameRate">videoFrameRate</a> <code>x</code>,<wbr/> this list will
-always include (<code>x</code>,<wbr/><code>x</code>).<wbr/></p>
-</li>
-<li>
-<p>Also,<wbr/> a camera device must either not support any
-<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a>,<wbr/>
-or support at least one
-normal <a href="https://developer.android.com/reference/android/media/CamcorderProfile.html">CamcorderProfile</a> that has
-<a href="https://developer.android.com/reference/android/media/CamcorderProfile.html#videoFrameRate">videoFrameRate</a> <code>x</code> &gt;= 24.<wbr/></p>
-</li>
-</ul>
-<p>For devices at the LIMITED level or above:</p>
-<ul>
-<li>For YUV_<wbr/>420_<wbr/>888 burst capture use case,<wbr/> this list will always include (<code>min</code>,<wbr/> <code>max</code>)
-and (<code>max</code>,<wbr/> <code>max</code>) where <code>min</code> &lt;= 15 and <code>max</code> = the maximum output frame rate of the
-maximum YUV_<wbr/>420_<wbr/>888 output size.<wbr/></li>
-</ul>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.aeCompensationRange">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as rangeInt]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Maximum and minimum exposure compensation values for
-<a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a>,<wbr/> in counts of <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a>,<wbr/>
-that are supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Range [0,<wbr/>0] indicates that exposure compensation is not supported.<wbr/></p>
-<p>For LIMITED and FULL devices,<wbr/> range must follow below requirements if exposure
-compensation is supported (<code>range != [0,<wbr/> 0]</code>):</p>
-<p><code>Min.<wbr/>exposure compensation * <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> &lt;= -2 EV</code></p>
-<p><code>Max.<wbr/>exposure compensation * <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> &gt;= 2 EV</code></p>
-<p>LEGACY devices may support a smaller range than this.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.aeCompensationStep">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Smallest step by which the exposure compensation
-can be changed.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Exposure Value (EV)
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is the unit for <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a>.<wbr/> For example,<wbr/> if this key has
-a value of <code>1/<wbr/>2</code>,<wbr/> then a setting of <code>-2</code> for <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> means
-that the target EV offset for the auto-exposure routine is -1 EV.<wbr/></p>
-<p>One unit of EV compensation changes the brightness of the captured image by a factor
-of two.<wbr/> +1 EV doubles the image brightness,<wbr/> while -1 EV halves the image brightness.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This must be less than or equal to 1/<wbr/>2.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.afAvailableModes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>af<wbr/>Available<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">List of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of auto-focus (AF) modes for <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> that are
-supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Not all the auto-focus modes may be supported by a
-given camera device.<wbr/> This entry lists the valid modes for
-<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> for this camera device.<wbr/></p>
-<p>All LIMITED and FULL mode camera devices will support OFF mode,<wbr/> and all
-camera devices with adjustable focuser units
-(<code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> &gt; 0</code>) will support AUTO mode.<wbr/></p>
-<p>LEGACY devices will support OFF mode only if they support
-focusing to infinity (by also setting <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> to
-<code>0.<wbr/>0f</code>).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.availableEffects">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>available<wbr/>Effects
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">List of enums (android.<wbr/>control.<wbr/>effect<wbr/>Mode).<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of color effects for <a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a> that are supported by this camera
-device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This list contains the color effect modes that can be applied to
-images produced by the camera device.<wbr/>
-Implementations are not expected to be consistent across all devices.<wbr/>
-If no color effect modes are available for a device,<wbr/> this will only list
-OFF.<wbr/></p>
-<p>A color effect will only be applied if
-<a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> != OFF.<wbr/>  OFF is always included in this list.<wbr/></p>
-<p>This control has no effect on the operation of other control routines such
-as auto-exposure,<wbr/> white balance,<wbr/> or focus.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.availableSceneModes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">List of enums (android.<wbr/>control.<wbr/>scene<wbr/>Mode).<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of scene modes for <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> that are supported by this camera
-device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This list contains scene modes that can be set for the camera device.<wbr/>
-Only scene modes that have been fully implemented for the
-camera device may be included here.<wbr/> Implementations are not expected
-to be consistent across all devices.<wbr/></p>
-<p>If no scene modes are supported by the camera device,<wbr/> this
-will be set to DISABLED.<wbr/> Otherwise DISABLED will not be listed.<wbr/></p>
-<p>FACE_<wbr/>PRIORITY is always listed if face detection is
-supported (i.<wbr/>e.<wbr/><code><a href="#static_android.statistics.info.maxFaceCount">android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Face<wbr/>Count</a> &gt;
-0</code>).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.availableVideoStabilizationModes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>available<wbr/>Video<wbr/>Stabilization<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">List of enums.<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of video stabilization modes for <a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>
-that are supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>OFF will always be listed.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.awbAvailableModes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>awb<wbr/>Available<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">List of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of auto-white-balance modes for <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> that are supported by this
-camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Not all the auto-white-balance modes may be supported by a
-given camera device.<wbr/> This entry lists the valid modes for
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> for this camera device.<wbr/></p>
-<p>All camera devices will support ON mode.<wbr/></p>
-<p>Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always support OFF
-mode,<wbr/> which enables application control of white balance,<wbr/> by using
-<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a> and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>(<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> must be set to TRANSFORM_<wbr/>MATRIX).<wbr/> This includes all FULL
-mode camera devices.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.maxRegions">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>control.<wbr/>max<wbr/>Regions
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of the maximum number of regions that can be used for metering in
-auto-exposure (AE),<wbr/> auto-white balance (AWB),<wbr/> and auto-focus (AF);
-this corresponds to the the maximum number of elements in
-<a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a>,<wbr/> <a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a>,<wbr/>
-and <a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a>.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Value must be &gt;= 0 for each element.<wbr/> For full-capability devices
-this value must be &gt;= 1 for AE and AF.<wbr/> The order of the elements is:
-<code>(AE,<wbr/> AWB,<wbr/> AF)</code>.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.maxRegionsAe">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [java_public]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum number of metering regions that can be used by the auto-exposure (AE)
-routine.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Value will be &gt;= 0.<wbr/> For FULL-capability devices,<wbr/> this
-value will be &gt;= 1.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This corresponds to the the maximum allowed number of elements in
-<a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This entry is private to the framework.<wbr/> Fill in
-maxRegions to have this entry be automatically populated.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.maxRegionsAwb">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [java_public]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum number of metering regions that can be used by the auto-white balance (AWB)
-routine.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Value will be &gt;= 0.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This corresponds to the the maximum allowed number of elements in
-<a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This entry is private to the framework.<wbr/> Fill in
-maxRegions to have this entry be automatically populated.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.maxRegionsAf">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [java_public]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum number of metering regions that can be used by the auto-focus (AF) routine.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Value will be &gt;= 0.<wbr/> For FULL-capability devices,<wbr/> this
-value will be &gt;= 1.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This corresponds to the the maximum allowed number of elements in
-<a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This entry is private to the framework.<wbr/> Fill in
-maxRegions to have this entry be automatically populated.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.sceneModeOverrides">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>scene<wbr/>Mode<wbr/>Overrides
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3 x length(availableSceneModes)
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Ordered list of auto-exposure,<wbr/> auto-white balance,<wbr/> and auto-focus
-settings to use with each available scene mode.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>For each available scene mode,<wbr/> the list must contain three
-entries containing the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> values used
-by the camera device.<wbr/> The entry order is <code>(aeMode,<wbr/> awbMode,<wbr/> afMode)</code>
-where aeMode has the lowest index position.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When a scene mode is enabled,<wbr/> the camera device is expected
-to override <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/>
-and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> with its preferred settings for
-that scene mode.<wbr/></p>
-<p>The order of this list matches that of availableSceneModes,<wbr/>
-with 3 entries for each mode.<wbr/>  The overrides listed
-for FACE_<wbr/>PRIORITY and FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT (if supported) are ignored,<wbr/>
-since for that mode the application-set <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> values are
-used instead,<wbr/> matching the behavior when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>
-is set to AUTO.<wbr/> It is recommended that the FACE_<wbr/>PRIORITY and
-FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT (if supported) overrides should be set to 0.<wbr/></p>
-<p>For example,<wbr/> if availableSceneModes contains
-<code>(FACE_<wbr/>PRIORITY,<wbr/> ACTION,<wbr/> NIGHT)</code>,<wbr/>  then the camera framework
-expects sceneModeOverrides to have 9 entries formatted like:
-<code>(0,<wbr/> 0,<wbr/> 0,<wbr/> ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> AUTO,<wbr/> CONTINUOUS_<wbr/>PICTURE,<wbr/>
-ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> INCANDESCENT,<wbr/> AUTO)</code>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>To maintain backward compatibility,<wbr/> this list will be made available
-in the static metadata of the camera service.<wbr/>  The camera service will
-use these values to set <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> when using a scene
-mode other than FACE_<wbr/>PRIORITY and FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT (if supported).<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.availableHighSpeedVideoConfigurations">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  5 x n
-                </span>
-              <span class="entry_type_visibility"> [hidden as highSpeedVideoConfiguration]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of available high speed video size,<wbr/> fps range and max batch size configurations
-supported by the camera device,<wbr/> in the format of (width,<wbr/> height,<wbr/> fps_<wbr/>min,<wbr/> fps_<wbr/>max,<wbr/> batch_<wbr/>size_<wbr/>max).<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>For each configuration,<wbr/> the fps_<wbr/>max &gt;= 120fps.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When CONSTRAINED_<wbr/>HIGH_<wbr/>SPEED_<wbr/>VIDEO is supported in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>,<wbr/>
-this metadata will list the supported high speed video size,<wbr/> fps range and max batch size
-configurations.<wbr/> All the sizes listed in this configuration will be a subset of the sizes
-reported by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">StreamConfigurationMap#getOutputSizes</a>
-for processed non-stalling formats.<wbr/></p>
-<p>For the high speed video use case,<wbr/> the application must
-select the video size and fps range from this metadata to configure the recording and
-preview streams and setup the recording requests.<wbr/> For example,<wbr/> if the application intends
-to do high speed recording,<wbr/> it can select the maximum size reported by this metadata to
-configure output streams.<wbr/> Once the size is selected,<wbr/> application can filter this metadata
-by selected size and get the supported fps ranges,<wbr/> and use these fps ranges to setup the
-recording requests.<wbr/> Note that for the use case of multiple output streams,<wbr/> application
-must select one unique size from this metadata to use (e.<wbr/>g.,<wbr/> preview and recording streams
-must have the same size).<wbr/> Otherwise,<wbr/> the high speed capture session creation will fail.<wbr/></p>
-<p>The min and max fps will be multiple times of 30fps.<wbr/></p>
-<p>High speed video streaming extends significant performance pressue to camera hardware,<wbr/>
-to achieve efficient high speed streaming,<wbr/> the camera device may have to aggregate
-multiple frames together and send to camera device for processing where the request
-controls are same for all the frames in this batch.<wbr/> Max batch size indicates
-the max possible number of frames the camera device will group together for this high
-speed stream configuration.<wbr/> This max batch size will be used to generate a high speed
-recording request list by
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a>.<wbr/>
-The max batch size for each configuration will satisfy below conditions:</p>
-<ul>
-<li>Each max batch size will be a divisor of its corresponding fps_<wbr/>max /<wbr/> 30.<wbr/> For example,<wbr/>
-if max_<wbr/>fps is 300,<wbr/> max batch size will only be 1,<wbr/> 2,<wbr/> 5,<wbr/> or 10.<wbr/></li>
-<li>The camera device may choose smaller internal batch size for each configuration,<wbr/> but
-the actual batch size will be a divisor of max batch size.<wbr/> For example,<wbr/> if the max batch
-size is 8,<wbr/> the actual batch size used by camera device will only be 1,<wbr/> 2,<wbr/> 4,<wbr/> or 8.<wbr/></li>
-<li>The max batch size in each configuration entry must be no larger than 32.<wbr/></li>
-</ul>
-<p>The camera device doesn't have to support batch mode to achieve high speed video recording,<wbr/>
-in such case,<wbr/> batch_<wbr/>size_<wbr/>max will be reported as 1 in each configuration entry.<wbr/></p>
-<p>This fps ranges in this configuration list can only be used to create requests
-that are submitted to a high speed camera capture session created by
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>.<wbr/>
-The fps ranges reported in this metadata must not be used to setup capture requests for
-normal capture session,<wbr/> or it will cause request error.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>All the sizes listed in this configuration will be a subset of the sizes reported by
-<a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> for processed non-stalling output formats.<wbr/>
-Note that for all high speed video configurations,<wbr/> HAL must be able to support a minimum
-of two streams,<wbr/> though the application might choose to configure just one stream.<wbr/></p>
-<p>The HAL may support multiple sensor modes for high speed outputs,<wbr/> for example,<wbr/> 120fps
-sensor mode and 120fps recording,<wbr/> 240fps sensor mode for 240fps recording.<wbr/> The application
-usually starts preview first,<wbr/> then starts recording.<wbr/> To avoid sensor mode switch caused
-stutter when starting recording as much as possible,<wbr/> the application may want to ensure
-the same sensor mode is used for preview and recording.<wbr/> Therefore,<wbr/> The HAL must advertise
-the variable fps range [30,<wbr/> fps_<wbr/>max] for each fixed fps range in this configuration list.<wbr/>
-For example,<wbr/> if the HAL advertises [120,<wbr/> 120] and [240,<wbr/> 240],<wbr/> the HAL must also advertise
-[30,<wbr/> 120] and [30,<wbr/> 240] for each configuration.<wbr/> In doing so,<wbr/> if the application intends to
-do 120fps recording,<wbr/> it can select [30,<wbr/> 120] to start preview,<wbr/> and [120,<wbr/> 120] to start
-recording.<wbr/> For these variable fps ranges,<wbr/> it's up to the HAL to decide the actual fps
-values that are suitable for smooth preview streaming.<wbr/> If the HAL sees different max_<wbr/>fps
-values that fall into different sensor modes in a sequence of requests,<wbr/> the HAL must
-switch the sensor mode as quick as possible to minimize the mode switch caused stutter.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.aeLockAvailable">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Lock<wbr/>Available
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">FALSE</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">TRUE</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether the camera device supports <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Devices with MANUAL_<wbr/>SENSOR capability or BURST_<wbr/>CAPTURE capability will always
-list <code>true</code>.<wbr/> This includes FULL devices.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.awbLockAvailable">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>awb<wbr/>Lock<wbr/>Available
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">FALSE</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">TRUE</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether the camera device supports <a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Devices with MANUAL_<wbr/>POST_<wbr/>PROCESSING capability or BURST_<wbr/>CAPTURE capability will
-always list <code>true</code>.<wbr/> This includes FULL devices.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.availableModes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>available<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">List of enums (android.<wbr/>control.<wbr/>mode).<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of control modes for <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> that are supported by this camera
-device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This list contains control modes that can be set for the camera device.<wbr/>
-LEGACY mode devices will always support AUTO mode.<wbr/> LIMITED and FULL
-devices will always support OFF,<wbr/> AUTO modes.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.control.postRawSensitivityBoostRange">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost<wbr/>Range
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as rangeInt]</span>
-
-
-
-
-                <div class="entry_type_notes">Range of supported post RAW sensitivitiy boosts</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Range of boosts for <a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> supported
-by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              ISO arithmetic units,<wbr/> the same as android.<wbr/>sensor.<wbr/>sensitivity
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Devices support post RAW sensitivity boost  will advertise
-<a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> key for controling
-post RAW sensitivity boost.<wbr/></p>
-<p>This key will be <code>null</code> for devices that do not support any RAW format
-outputs.<wbr/> For devices that do support RAW format outputs,<wbr/> this key will always
-present,<wbr/> and if a device does not support post RAW sensitivity boost,<wbr/> it will
-list <code>(100,<wbr/> 100)</code> in this key.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This key is added in HAL3.<wbr/>4.<wbr/> For HAL3.<wbr/>3 or earlier devices,<wbr/> camera framework will
-generate this key as <code>(100,<wbr/> 100)</code> if device supports any of RAW output formats.<wbr/>
-All HAL3.<wbr/>4 and above devices should list this key if device supports any of RAW
-output formats.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.control.aePrecaptureId">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Id
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The ID sent with the latest
-CAMERA2_<wbr/>TRIGGER_<wbr/>PRECAPTURE_<wbr/>METERING call</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Must be 0 if no
-CAMERA2_<wbr/>TRIGGER_<wbr/>PRECAPTURE_<wbr/>METERING trigger received yet
-by HAL.<wbr/> Always updated even if AE algorithm ignores the
-trigger</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.aeAntibandingMode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>The camera device will not adjust exposure duration to
-avoid banding problems.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">50HZ</span>
-                    <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to
-avoid banding problems with 50Hz illumination sources.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">60HZ</span>
-                    <span class="entry_type_enum_notes"><p>The camera device will adjust exposure duration to
-avoid banding problems with 60Hz illumination
-sources.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">AUTO</span>
-                    <span class="entry_type_enum_notes"><p>The camera device will automatically adapt its
-antibanding routine to the current illumination
-condition.<wbr/> This is the default mode if AUTO is
-available on given camera device.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired setting for the camera device's auto-exposure
-algorithm's antibanding compensation.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Some kinds of lighting fixtures,<wbr/> such as some fluorescent
-lights,<wbr/> flicker at the rate of the power supply frequency
-(60Hz or 50Hz,<wbr/> depending on country).<wbr/> While this is
-typically not noticeable to a person,<wbr/> it can be visible to
-a camera device.<wbr/> If a camera sets its exposure time to the
-wrong value,<wbr/> the flicker may become visible in the
-viewfinder as flicker or in a final captured image,<wbr/> as a
-set of variable-brightness bands across the image.<wbr/></p>
-<p>Therefore,<wbr/> the auto-exposure routines of camera devices
-include antibanding routines that ensure that the chosen
-exposure value will not cause such banding.<wbr/> The choice of
-exposure time depends on the rate of flicker,<wbr/> which the
-camera device can detect automatically,<wbr/> or the expected
-rate can be selected by the application using this
-control.<wbr/></p>
-<p>A given camera device may not support all of the possible
-options for the antibanding mode.<wbr/> The
-<a href="#static_android.control.aeAvailableAntibandingModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Antibanding<wbr/>Modes</a> key contains
-the available modes for a given camera device.<wbr/></p>
-<p>AUTO mode is the default if it is available on given
-camera device.<wbr/> When AUTO mode is not available,<wbr/> the
-default will be either 50HZ or 60HZ,<wbr/> and both 50HZ
-and 60HZ will be available.<wbr/></p>
-<p>If manual exposure control is enabled (by setting
-<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/>
-then this setting has no effect,<wbr/> and the application must
-ensure it selects exposure times that do not cause banding
-issues.<wbr/> The <a href="#dynamic_android.statistics.sceneFlicker">android.<wbr/>statistics.<wbr/>scene<wbr/>Flicker</a> key can assist
-the application in this.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For all capture request templates,<wbr/> this field must be set
-to AUTO if AUTO mode is available.<wbr/> If AUTO is not available,<wbr/>
-the default must be either 50HZ or 60HZ,<wbr/> and both 50HZ and
-60HZ must be available.<wbr/></p>
-<p>If manual exposure control is enabled (by setting
-<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> to OFF),<wbr/>
-then the exposure values provided by the application must not be
-adjusted for antibanding.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.aeExposureCompensation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Adjustment to auto-exposure (AE) target image
-brightness.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Compensation steps
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The adjustment is measured as a count of steps,<wbr/> with the
-step size defined by <a href="#static_android.control.aeCompensationStep">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Step</a> and the
-allowed range by <a href="#static_android.control.aeCompensationRange">android.<wbr/>control.<wbr/>ae<wbr/>Compensation<wbr/>Range</a>.<wbr/></p>
-<p>For example,<wbr/> if the exposure value (EV) step is 0.<wbr/>333,<wbr/> '6'
-will mean an exposure compensation of +2 EV; -3 will mean an
-exposure compensation of -1 EV.<wbr/> One EV represents a doubling
-of image brightness.<wbr/> Note that this control will only be
-effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF.<wbr/> This control
-will take effect even when <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> <code>== true</code>.<wbr/></p>
-<p>In the event of exposure compensation value being changed,<wbr/> camera device
-may take several frames to reach the newly requested exposure target.<wbr/>
-During that time,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> field will be in the SEARCHING
-state.<wbr/> Once the new exposure target is reached,<wbr/> <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> will
-change from SEARCHING to either CONVERGED,<wbr/> LOCKED (if AE lock is enabled),<wbr/> or
-FLASH_<wbr/>REQUIRED (if the scene is too dark for still capture).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.aeLock">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Lock
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Auto-exposure lock is disabled; the AE algorithm
-is free to update its parameters.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>Auto-exposure lock is enabled; the AE algorithm
-must not update the exposure and sensitivity parameters
-while the lock is active.<wbr/></p>
-<p><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> setting changes
-will still take effect while auto-exposure is locked.<wbr/></p>
-<p>Some rare LEGACY devices may not support
-this,<wbr/> in which case the value will always be overridden to OFF.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether auto-exposure (AE) is currently locked to its latest
-calculated values.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to <code>true</code> (ON),<wbr/> the AE algorithm is locked to its latest parameters,<wbr/>
-and will not change exposure settings until the lock is set to <code>false</code> (OFF).<wbr/></p>
-<p>Note that even when AE is locked,<wbr/> the flash may be fired if
-the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>AUTO_<wbr/>FLASH /<wbr/>
-ON_<wbr/>ALWAYS_<wbr/>FLASH /<wbr/> ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE.<wbr/></p>
-<p>When <a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a> is changed,<wbr/> even if the AE lock
-is ON,<wbr/> the camera device will still adjust its exposure value.<wbr/></p>
-<p>If AE precapture is triggered (see <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>)
-when AE is already locked,<wbr/> the camera device will not change the exposure time
-(<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>) and sensitivity (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>)
-parameters.<wbr/> The flash may be fired if the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>
-is ON_<wbr/>AUTO_<wbr/>FLASH/<wbr/>ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE and the scene is too dark.<wbr/> If the
-<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> the scene may become overexposed.<wbr/>
-Similarly,<wbr/> AE precapture trigger CANCEL has no effect when AE is already locked.<wbr/></p>
-<p>When an AE precapture sequence is triggered,<wbr/> AE unlock will not be able to unlock
-the AE if AE is locked by the camera device internally during precapture metering
-sequence In other words,<wbr/> submitting requests with AE unlock has no effect for an
-ongoing precapture metering sequence.<wbr/> Otherwise,<wbr/> the precapture metering sequence
-will never succeed in a sequence of preview requests where AE lock is always set
-to <code>false</code>.<wbr/></p>
-<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that
-get locked do not necessarily correspond to the settings that were present in the
-latest capture result received from the camera device,<wbr/> since additional captures
-and AE updates may have occurred even before the result was sent out.<wbr/> If an
-application is switching between automatic and manual control and wishes to eliminate
-any flicker during the switch,<wbr/> the following procedure is recommended:</p>
-<ol>
-<li>Starting in auto-AE mode:</li>
-<li>Lock AE</li>
-<li>Wait for the first result to be output that has the AE locked</li>
-<li>Copy exposure settings from that result into a request,<wbr/> set the request to manual AE</li>
-<li>Submit the capture request,<wbr/> proceed to run manual AE as desired.<wbr/></li>
-</ol>
-<p>See <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE lock related state transition details.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.aeMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is disabled.<wbr/></p>
-<p>The application-selected <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
-<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> and
-<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are used by the camera
-device,<wbr/> along with android.<wbr/>flash.<wbr/>* fields,<wbr/> if there's
-a flash unit for this camera device.<wbr/></p>
-<p>Note that auto-white balance (AWB) and auto-focus (AF)
-behavior is device dependent when AE is in OFF mode.<wbr/>
-To have consistent behavior across different devices,<wbr/>
-it is recommended to either set AWB and AF to OFF mode
-or lock AWB and AF before setting AE to OFF.<wbr/>
-See <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a>,<wbr/> and <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>
-for more details.<wbr/></p>
-<p>LEGACY devices do not support the OFF mode and will
-override attempts to use this value to ON.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's autoexposure routine is active,<wbr/>
-with no flash control.<wbr/></p>
-<p>The application's values for
-<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
-<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and
-<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> are ignored.<wbr/> The
-application has control over the various
-android.<wbr/>flash.<wbr/>* fields.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON_AUTO_FLASH</span>
-                    <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls
-the camera's flash unit,<wbr/> firing it in low-light
-conditions.<wbr/></p>
-<p>The flash may be fired during a precapture sequence
-(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and
-may be fired for captures for which the
-<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to
-STILL_<wbr/>CAPTURE</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON_ALWAYS_FLASH</span>
-                    <span class="entry_type_enum_notes"><p>Like ON,<wbr/> except that the camera device also controls
-the camera's flash unit,<wbr/> always firing it for still
-captures.<wbr/></p>
-<p>The flash may be fired during a precapture sequence
-(triggered by <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>) and
-will always be fired for captures for which the
-<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> field is set to
-STILL_<wbr/>CAPTURE</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON_AUTO_FLASH_REDEYE</span>
-                    <span class="entry_type_enum_notes"><p>Like ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/> but with automatic red eye
-reduction.<wbr/></p>
-<p>If deemed necessary by the camera device,<wbr/> a red eye
-reduction flash will fire during the precapture
-sequence.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired mode for the camera device's
-auto-exposure routine.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.aeAvailableModes">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is
-AUTO.<wbr/></p>
-<p>When set to any of the ON modes,<wbr/> the camera device's
-auto-exposure routine is enabled,<wbr/> overriding the
-application's selected exposure time,<wbr/> sensor sensitivity,<wbr/>
-and frame duration (<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
-<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and
-<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>).<wbr/> If one of the FLASH modes
-is selected,<wbr/> the camera device's flash unit controls are
-also overridden.<wbr/></p>
-<p>The FLASH modes are only available if the camera device
-has a flash unit (<a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> is <code>true</code>).<wbr/></p>
-<p>If flash TORCH mode is desired,<wbr/> this field must be set to
-ON or OFF,<wbr/> and <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> set to TORCH.<wbr/></p>
-<p>When set to any of the ON modes,<wbr/> the values chosen by the
-camera device auto-exposure routine for the overridden
-fields for a given capture will be available in its
-CaptureResult.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.aeRegions">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>ae<wbr/>Regions
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  5 x area_count
-                </span>
-              <span class="entry_type_visibility"> [public as meteringRectangle]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of metering areas to use for auto-exposure adjustment.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
-            </td>
-
-            <td class="entry_range">
-              <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Not available if <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a> is 0.<wbr/>
-Otherwise will always be present.<wbr/></p>
-<p>The maximum number of regions supported by the device is determined by the value
-of <a href="#static_android.control.maxRegionsAe">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Ae</a>.<wbr/></p>
-<p>The coordinate system is based on the active pixel array,<wbr/>
-with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
-(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
-bottom-right pixel in the active pixel array.<wbr/></p>
-<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight
-for every pixel in the area.<wbr/> This means that a large metering area
-with the same weight as a smaller area will have more effect in
-the metering result.<wbr/> Metering areas can partially overlap and the
-camera device will add the weights in the overlap region.<wbr/></p>
-<p>The weights are relative to weights of other exposure metering regions,<wbr/> so if only one
-region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0
-weight is ignored.<wbr/></p>
-<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
-camera device.<wbr/></p>
-<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
-capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
-region and output only the intersection rectangle as the metering region in the result
-metadata.<wbr/>  If the region is entirely outside the crop region,<wbr/> it will be ignored and
-not reported in the result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL level representation of MeteringRectangle[] is a
-int[5 * area_<wbr/>count].<wbr/>
-Every five elements represent a metering region of
-(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
-The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
-exclusive on xmax and ymax.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.aeTargetFpsRange">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as rangeInt]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Range over which the auto-exposure routine can
-adjust the capture frame rate to maintain good
-exposure.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Frames per second (FPS)
-            </td>
-
-            <td class="entry_range">
-              <p>Any of the entries in <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Only constrains auto-exposure (AE) algorithm,<wbr/> not
-manual control of <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a> and
-<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.aePrecaptureTrigger">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">IDLE</span>
-                    <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">START</span>
-                    <span class="entry_type_enum_notes"><p>The precapture metering sequence will be started
-by the camera device.<wbr/></p>
-<p>The exact effect of the precapture trigger depends on
-the current AE mode and state.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CANCEL</span>
-                    <span class="entry_type_enum_notes"><p>The camera device will cancel any currently active or completed
-precapture metering sequence,<wbr/> the auto-exposure routine will return to its
-initial state.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether the camera device will trigger a precapture
-metering sequence when it processes this request.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This entry is normally set to IDLE,<wbr/> or is not
-included at all in the request settings.<wbr/> When included and
-set to START,<wbr/> the camera device will trigger the auto-exposure (AE)
-precapture metering sequence.<wbr/></p>
-<p>When set to CANCEL,<wbr/> the camera device will cancel any active
-precapture metering trigger,<wbr/> and return to its initial AE state.<wbr/>
-If a precapture metering sequence is already completed,<wbr/> and the camera
-device has implicitly locked the AE for subsequent still capture,<wbr/> the
-CANCEL trigger will unlock the AE and return to its initial AE state.<wbr/></p>
-<p>The precapture sequence should be triggered before starting a
-high-quality still capture for final metering decisions to
-be made,<wbr/> and for firing pre-capture flash pulses to estimate
-scene brightness and required final capture flash power,<wbr/> when
-the flash is enabled.<wbr/></p>
-<p>Normally,<wbr/> this entry should be set to START for only a
-single request,<wbr/> and the application should wait until the
-sequence completes before starting a new one.<wbr/></p>
-<p>When a precapture metering sequence is finished,<wbr/> the camera device
-may lock the auto-exposure routine internally to be able to accurately expose the
-subsequent still capture image (<code><a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> == STILL_<wbr/>CAPTURE</code>).<wbr/>
-For this case,<wbr/> the AE may not resume normal scan if no subsequent still capture is
-submitted.<wbr/> To ensure that the AE routine restarts normal scan,<wbr/> the application should
-submit a request with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == true</code>,<wbr/> followed by a request
-with <code><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> == false</code>,<wbr/> if the application decides not to submit a
-still capture request after the precapture sequence completes.<wbr/> Alternatively,<wbr/> for
-API level 23 or newer devices,<wbr/> the CANCEL can be used to unlock the camera device
-internally locked AE if the application doesn't submit a still capture request after
-the AE precapture trigger.<wbr/> Note that,<wbr/> the CANCEL was added in API level 23,<wbr/> and must not
-be used in devices that have earlier API levels.<wbr/></p>
-<p>The exact effect of auto-exposure (AE) precapture trigger
-depends on the current AE mode and state; see
-<a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> for AE precapture state transition
-details.<wbr/></p>
-<p>On LEGACY-level devices,<wbr/> the precapture trigger is not supported;
-capturing a high-resolution JPEG image will automatically trigger a
-precapture sequence before the high-resolution capture,<wbr/> including
-potentially firing a pre-capture flash.<wbr/></p>
-<p>Using the precapture trigger and the auto-focus trigger <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>
-simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between
-the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a
-focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous
-trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and
-changes to <a href="#dynamic_android.control.aeState">android.<wbr/>control.<wbr/>ae<wbr/>State</a> indicating the start of the precapture sequence,<wbr/> for
-example.<wbr/></p>
-<p>If both the precapture and the auto-focus trigger are activated on the same request,<wbr/> then
-the camera device will complete them in the optimal order for that device.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL must support triggering the AE precapture trigger while an AF trigger is active
-(and vice versa),<wbr/> or at the same time as the AF trigger.<wbr/>  It is acceptable for the HAL to
-treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the
-AE trigger.<wbr/>  Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/>
-to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.aeState">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>ae<wbr/>State
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">INACTIVE</span>
-                    <span class="entry_type_enum_notes"><p>AE is off or recently reset.<wbr/></p>
-<p>When a camera device is opened,<wbr/> it starts in
-this state.<wbr/> This is a transient state,<wbr/> the camera device may skip reporting
-this state in capture result.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SEARCHING</span>
-                    <span class="entry_type_enum_notes"><p>AE doesn't yet have a good set of control values
-for the current scene.<wbr/></p>
-<p>This is a transient state,<wbr/> the camera device may skip
-reporting this state in capture result.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CONVERGED</span>
-                    <span class="entry_type_enum_notes"><p>AE has a good set of control values for the
-current scene.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">LOCKED</span>
-                    <span class="entry_type_enum_notes"><p>AE has been locked.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FLASH_REQUIRED</span>
-                    <span class="entry_type_enum_notes"><p>AE has a good set of control values,<wbr/> but flash
-needs to be fired for good quality still
-capture.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PRECAPTURE</span>
-                    <span class="entry_type_enum_notes"><p>AE has been asked to do a precapture sequence
-and is currently executing it.<wbr/></p>
-<p>Precapture can be triggered through setting
-<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> to START.<wbr/> Currently
-active and completed (if it causes camera device internal AE lock) precapture
-metering sequence can be canceled through setting
-<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> to CANCEL.<wbr/></p>
-<p>Once PRECAPTURE completes,<wbr/> AE will transition to CONVERGED
-or FLASH_<wbr/>REQUIRED as appropriate.<wbr/> This is a transient
-state,<wbr/> the camera device may skip reporting this state in
-capture result.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Current state of the auto-exposure (AE) algorithm.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Switching between or enabling AE modes (<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>) always
-resets the AE state to INACTIVE.<wbr/> Similarly,<wbr/> switching between <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>,<wbr/>
-or <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> if <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code> resets all
-the algorithm states to INACTIVE.<wbr/></p>
-<p>The camera device can do several state transitions between two results,<wbr/> if it is
-allowed by the state transition table.<wbr/> For example: INACTIVE may never actually be
-seen in a result.<wbr/></p>
-<p>The state in the result is the state for this image (in sync with this image): if
-AE state becomes CONVERGED,<wbr/> then the image data associated with this result should
-be good to use.<wbr/></p>
-<p>Below are state transition tables for different AE modes.<wbr/></p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center"></td>
-<td align="center">INACTIVE</td>
-<td align="center">Camera device auto exposure algorithm is disabled</td>
-</tr>
-</tbody>
-</table>
-<p>When <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is AE_<wbr/>MODE_<wbr/>ON_<wbr/>*:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">Camera device initiates AE scan</td>
-<td align="center">SEARCHING</td>
-<td align="center">Values changing</td>
-</tr>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td>
-<td align="center">LOCKED</td>
-<td align="center">Values locked</td>
-</tr>
-<tr>
-<td align="center">SEARCHING</td>
-<td align="center">Camera device finishes AE scan</td>
-<td align="center">CONVERGED</td>
-<td align="center">Good values,<wbr/> not changing</td>
-</tr>
-<tr>
-<td align="center">SEARCHING</td>
-<td align="center">Camera device finishes AE scan</td>
-<td align="center">FLASH_<wbr/>REQUIRED</td>
-<td align="center">Converged but too dark w/<wbr/>o flash</td>
-</tr>
-<tr>
-<td align="center">SEARCHING</td>
-<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td>
-<td align="center">LOCKED</td>
-<td align="center">Values locked</td>
-</tr>
-<tr>
-<td align="center">CONVERGED</td>
-<td align="center">Camera device initiates AE scan</td>
-<td align="center">SEARCHING</td>
-<td align="center">Values changing</td>
-</tr>
-<tr>
-<td align="center">CONVERGED</td>
-<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td>
-<td align="center">LOCKED</td>
-<td align="center">Values locked</td>
-</tr>
-<tr>
-<td align="center">FLASH_<wbr/>REQUIRED</td>
-<td align="center">Camera device initiates AE scan</td>
-<td align="center">SEARCHING</td>
-<td align="center">Values changing</td>
-</tr>
-<tr>
-<td align="center">FLASH_<wbr/>REQUIRED</td>
-<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td>
-<td align="center">LOCKED</td>
-<td align="center">Values locked</td>
-</tr>
-<tr>
-<td align="center">LOCKED</td>
-<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td>
-<td align="center">SEARCHING</td>
-<td align="center">Values not good after unlock</td>
-</tr>
-<tr>
-<td align="center">LOCKED</td>
-<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td>
-<td align="center">CONVERGED</td>
-<td align="center">Values good after unlock</td>
-</tr>
-<tr>
-<td align="center">LOCKED</td>
-<td align="center"><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td>
-<td align="center">FLASH_<wbr/>REQUIRED</td>
-<td align="center">Exposure good,<wbr/> but too dark</td>
-</tr>
-<tr>
-<td align="center">PRECAPTURE</td>
-<td align="center">Sequence done.<wbr/> <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is OFF</td>
-<td align="center">CONVERGED</td>
-<td align="center">Ready for high-quality capture</td>
-</tr>
-<tr>
-<td align="center">PRECAPTURE</td>
-<td align="center">Sequence done.<wbr/> <a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a> is ON</td>
-<td align="center">LOCKED</td>
-<td align="center">Ready for high-quality capture</td>
-</tr>
-<tr>
-<td align="center">LOCKED</td>
-<td align="center">aeLock is ON and aePrecaptureTrigger is START</td>
-<td align="center">LOCKED</td>
-<td align="center">Precapture trigger is ignored when AE is already locked</td>
-</tr>
-<tr>
-<td align="center">LOCKED</td>
-<td align="center">aeLock is ON and aePrecaptureTrigger is CANCEL</td>
-<td align="center">LOCKED</td>
-<td align="center">Precapture trigger is ignored when AE is already locked</td>
-</tr>
-<tr>
-<td align="center">Any state (excluding LOCKED)</td>
-<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is START</td>
-<td align="center">PRECAPTURE</td>
-<td align="center">Start AE precapture metering sequence</td>
-</tr>
-<tr>
-<td align="center">Any state (excluding LOCKED)</td>
-<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is CANCEL</td>
-<td align="center">INACTIVE</td>
-<td align="center">Currently active precapture metering sequence is canceled</td>
-</tr>
-</tbody>
-</table>
-<p>For the above table,<wbr/> the camera device may skip reporting any state changes that happen
-without application intervention (i.<wbr/>e.<wbr/> mode switch,<wbr/> trigger,<wbr/> locking).<wbr/> Any state that
-can be skipped in that manner is called a transient state.<wbr/></p>
-<p>For example,<wbr/> for above AE modes (AE_<wbr/>MODE_<wbr/>ON_<wbr/>*),<wbr/> in addition to the state transitions
-listed in above table,<wbr/> it is also legal for the camera device to skip one or more
-transient states between two results.<wbr/> See below table for examples:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">Camera device finished AE scan</td>
-<td align="center">CONVERGED</td>
-<td align="center">Values are already good,<wbr/> transient states are skipped by camera device.<wbr/></td>
-</tr>
-<tr>
-<td align="center">Any state (excluding LOCKED)</td>
-<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is START,<wbr/> sequence done</td>
-<td align="center">FLASH_<wbr/>REQUIRED</td>
-<td align="center">Converged but too dark w/<wbr/>o flash after a precapture sequence,<wbr/> transient states are skipped by camera device.<wbr/></td>
-</tr>
-<tr>
-<td align="center">Any state (excluding LOCKED)</td>
-<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is START,<wbr/> sequence done</td>
-<td align="center">CONVERGED</td>
-<td align="center">Converged after a precapture sequence,<wbr/> transient states are skipped by camera device.<wbr/></td>
-</tr>
-<tr>
-<td align="center">Any state (excluding LOCKED)</td>
-<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is CANCEL,<wbr/> converged</td>
-<td align="center">FLASH_<wbr/>REQUIRED</td>
-<td align="center">Converged but too dark w/<wbr/>o flash after a precapture sequence is canceled,<wbr/> transient states are skipped by camera device.<wbr/></td>
-</tr>
-<tr>
-<td align="center">Any state (excluding LOCKED)</td>
-<td align="center"><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is CANCEL,<wbr/> converged</td>
-<td align="center">CONVERGED</td>
-<td align="center">Converged after a precapture sequenceis canceled,<wbr/> transient states are skipped by camera device.<wbr/></td>
-</tr>
-<tr>
-<td align="center">CONVERGED</td>
-<td align="center">Camera device finished AE scan</td>
-<td align="center">FLASH_<wbr/>REQUIRED</td>
-<td align="center">Converged but too dark w/<wbr/>o flash after a new scan,<wbr/> transient states are skipped by camera device.<wbr/></td>
-</tr>
-<tr>
-<td align="center">FLASH_<wbr/>REQUIRED</td>
-<td align="center">Camera device finished AE scan</td>
-<td align="center">CONVERGED</td>
-<td align="center">Converged after a new scan,<wbr/> transient states are skipped by camera device.<wbr/></td>
-</tr>
-</tbody>
-</table>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.afMode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>af<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>The auto-focus routine does not control the lens;
-<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> is controlled by the
-application.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">AUTO</span>
-                    <span class="entry_type_enum_notes"><p>Basic automatic focus mode.<wbr/></p>
-<p>In this mode,<wbr/> the lens does not move unless
-the autofocus trigger action is called.<wbr/> When that trigger
-is activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to
-the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/></p>
-<p>Always supported if lens is not fixed focus.<wbr/></p>
-<p>Use <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> to determine if lens
-is fixed-focus.<wbr/></p>
-<p>Triggering AF_<wbr/>CANCEL resets the lens position to default,<wbr/>
-and sets the AF state to INACTIVE.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MACRO</span>
-                    <span class="entry_type_enum_notes"><p>Close-up focusing mode.<wbr/></p>
-<p>In this mode,<wbr/> the lens does not move unless the
-autofocus trigger action is called.<wbr/> When that trigger is
-activated,<wbr/> AF will transition to ACTIVE_<wbr/>SCAN,<wbr/> then to
-the outcome of the scan (FOCUSED or NOT_<wbr/>FOCUSED).<wbr/> This
-mode is optimized for focusing on objects very close to
-the camera.<wbr/></p>
-<p>When that trigger is activated,<wbr/> AF will transition to
-ACTIVE_<wbr/>SCAN,<wbr/> then to the outcome of the scan (FOCUSED or
-NOT_<wbr/>FOCUSED).<wbr/> Triggering cancel AF resets the lens
-position to default,<wbr/> and sets the AF state to
-INACTIVE.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CONTINUOUS_VIDEO</span>
-                    <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens
-position continually to attempt to provide a
-constantly-in-focus image stream.<wbr/></p>
-<p>The focusing behavior should be suitable for good quality
-video recording; typically this means slower focus
-movement and no overshoots.<wbr/> When the AF trigger is not
-involved,<wbr/> the AF algorithm should start in INACTIVE state,<wbr/>
-and then transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED
-states as appropriate.<wbr/> When the AF trigger is activated,<wbr/>
-the algorithm should immediately transition into
-AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the
-lens position until a cancel AF trigger is received.<wbr/></p>
-<p>Once cancel is received,<wbr/> the algorithm should transition
-back to INACTIVE and resume passive scan.<wbr/> Note that this
-behavior is not identical to CONTINUOUS_<wbr/>PICTURE,<wbr/> since an
-ongoing PASSIVE_<wbr/>SCAN must immediately be
-canceled.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CONTINUOUS_PICTURE</span>
-                    <span class="entry_type_enum_notes"><p>In this mode,<wbr/> the AF algorithm modifies the lens
-position continually to attempt to provide a
-constantly-in-focus image stream.<wbr/></p>
-<p>The focusing behavior should be suitable for still image
-capture; typically this means focusing as fast as
-possible.<wbr/> When the AF trigger is not involved,<wbr/> the AF
-algorithm should start in INACTIVE state,<wbr/> and then
-transition into PASSIVE_<wbr/>SCAN and PASSIVE_<wbr/>FOCUSED states as
-appropriate as it attempts to maintain focus.<wbr/> When the AF
-trigger is activated,<wbr/> the algorithm should finish its
-PASSIVE_<wbr/>SCAN if active,<wbr/> and then transition into
-AF_<wbr/>FOCUSED or AF_<wbr/>NOT_<wbr/>FOCUSED as appropriate,<wbr/> and lock the
-lens position until a cancel AF trigger is received.<wbr/></p>
-<p>When the AF cancel trigger is activated,<wbr/> the algorithm
-should transition back to INACTIVE and then act as if it
-has just been started.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">EDOF</span>
-                    <span class="entry_type_enum_notes"><p>Extended depth of field (digital focus) mode.<wbr/></p>
-<p>The camera device will produce images with an extended
-depth of field automatically; no special focusing
-operations need to be done before taking a picture.<wbr/></p>
-<p>AF triggers are ignored,<wbr/> and the AF state will always be
-INACTIVE.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether auto-focus (AF) is currently enabled,<wbr/> and what
-mode it is set to.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.afAvailableModes">android.<wbr/>control.<wbr/>af<wbr/>Available<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> = AUTO and the lens is not fixed focus
-(i.<wbr/>e.<wbr/> <code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> &gt; 0</code>).<wbr/> Also note that
-when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/> the behavior of AF is device
-dependent.<wbr/> It is recommended to lock AF by using <a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> before
-setting <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> to OFF,<wbr/> or set AF mode to OFF when AE is OFF.<wbr/></p>
-<p>If the lens is controlled by the camera device auto-focus algorithm,<wbr/>
-the camera device will report the current AF status in <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a>
-in result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When afMode is AUTO or MACRO,<wbr/> the lens must not move until an AF trigger is sent in a
-request (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a> <code>==</code> START).<wbr/> After an AF trigger,<wbr/> the afState will end
-up with either FOCUSED_<wbr/>LOCKED or NOT_<wbr/>FOCUSED_<wbr/>LOCKED state (see
-<a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> which indicates that the lens is
-locked and will not move.<wbr/> If camera movement (e.<wbr/>g.<wbr/> tilting camera) causes the lens to move
-after the lens is locked,<wbr/> the HAL must compensate this movement appropriately such that
-the same focal plane remains in focus.<wbr/></p>
-<p>When afMode is one of the continuous auto focus modes,<wbr/> the HAL is free to start a AF
-scan whenever it's not locked.<wbr/> When the lens is locked after an AF trigger
-(see <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for detailed state transitions),<wbr/> the HAL should maintain the
-same lock behavior as above.<wbr/></p>
-<p>When afMode is OFF,<wbr/> the application controls focus manually.<wbr/> The accuracy of the
-focus distance control depends on the <a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a>.<wbr/>
-However,<wbr/> the lens must not move regardless of the camera movement for any focus distance
-manual control.<wbr/></p>
-<p>To put this in concrete terms,<wbr/> if the camera has lens elements which may move based on
-camera orientation or motion (e.<wbr/>g.<wbr/> due to gravity),<wbr/> then the HAL must drive the lens to
-remain in a fixed position invariant to the camera's orientation or motion,<wbr/> for example,<wbr/>
-by using accelerometer measurements in the lens control logic.<wbr/> This is a typical issue
-that will arise on camera modules with open-loop VCMs.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.afRegions">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>af<wbr/>Regions
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  5 x area_count
-                </span>
-              <span class="entry_type_visibility"> [public as meteringRectangle]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of metering areas to use for auto-focus.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
-            </td>
-
-            <td class="entry_range">
-              <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Not available if <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a> is 0.<wbr/>
-Otherwise will always be present.<wbr/></p>
-<p>The maximum number of focus areas supported by the device is determined by the value
-of <a href="#static_android.control.maxRegionsAf">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Af</a>.<wbr/></p>
-<p>The coordinate system is based on the active pixel array,<wbr/>
-with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
-(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
-bottom-right pixel in the active pixel array.<wbr/></p>
-<p>The weight must be within <code>[0,<wbr/> 1000]</code>,<wbr/> and represents a weight
-for every pixel in the area.<wbr/> This means that a large metering area
-with the same weight as a smaller area will have more effect in
-the metering result.<wbr/> Metering areas can partially overlap and the
-camera device will add the weights in the overlap region.<wbr/></p>
-<p>The weights are relative to weights of other metering regions,<wbr/> so if only one region
-is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with 0 weight is
-ignored.<wbr/></p>
-<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
-camera device.<wbr/></p>
-<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
-capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
-region and output only the intersection rectangle as the metering region in the result
-metadata.<wbr/> If the region is entirely outside the crop region,<wbr/> it will be ignored and
-not reported in the result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL level representation of MeteringRectangle[] is a
-int[5 * area_<wbr/>count].<wbr/>
-Every five elements represent a metering region of
-(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
-The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
-exclusive on xmax and ymax.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.afTrigger">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>af<wbr/>Trigger
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">IDLE</span>
-                    <span class="entry_type_enum_notes"><p>The trigger is idle.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">START</span>
-                    <span class="entry_type_enum_notes"><p>Autofocus will trigger now.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CANCEL</span>
-                    <span class="entry_type_enum_notes"><p>Autofocus will return to its initial
-state,<wbr/> and cancel any currently active trigger.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether the camera device will trigger autofocus for this request.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This entry is normally set to IDLE,<wbr/> or is not
-included at all in the request settings.<wbr/></p>
-<p>When included and set to START,<wbr/> the camera device will trigger the
-autofocus algorithm.<wbr/> If autofocus is disabled,<wbr/> this trigger has no effect.<wbr/></p>
-<p>When set to CANCEL,<wbr/> the camera device will cancel any active trigger,<wbr/>
-and return to its initial AF state.<wbr/></p>
-<p>Generally,<wbr/> applications should set this entry to START or CANCEL for only a
-single capture,<wbr/> and then return it to IDLE (or not set at all).<wbr/> Specifying
-START for multiple captures in a row means restarting the AF operation over
-and over again.<wbr/></p>
-<p>See <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a> for what the trigger means for each AF mode.<wbr/></p>
-<p>Using the autofocus trigger and the precapture trigger <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>
-simultaneously is allowed.<wbr/> However,<wbr/> since these triggers often require cooperation between
-the auto-focus and auto-exposure routines (for example,<wbr/> the may need to be enabled for a
-focus sweep),<wbr/> the camera device may delay acting on a later trigger until the previous
-trigger has been fully handled.<wbr/> This may lead to longer intervals between the trigger and
-changes to <a href="#dynamic_android.control.afState">android.<wbr/>control.<wbr/>af<wbr/>State</a>,<wbr/> for example.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL must support triggering the AF trigger while an AE precapture trigger is active
-(and vice versa),<wbr/> or at the same time as the AE trigger.<wbr/>  It is acceptable for the HAL to
-treat these as two consecutive triggers,<wbr/> for example handling the AF trigger and then the
-AE trigger.<wbr/>  Or the HAL may choose to optimize the case with both triggers fired at once,<wbr/>
-to minimize the latency for converging both focus and exposure/<wbr/>flash usage.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.afState">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>af<wbr/>State
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">INACTIVE</span>
-                    <span class="entry_type_enum_notes"><p>AF is off or has not yet tried to scan/<wbr/>been asked
-to scan.<wbr/></p>
-<p>When a camera device is opened,<wbr/> it starts in this
-state.<wbr/> This is a transient state,<wbr/> the camera device may
-skip reporting this state in capture
-result.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PASSIVE_SCAN</span>
-                    <span class="entry_type_enum_notes"><p>AF is currently performing an AF scan initiated the
-camera device in a continuous autofocus mode.<wbr/></p>
-<p>Only used by CONTINUOUS_<wbr/>* AF modes.<wbr/> This is a transient
-state,<wbr/> the camera device may skip reporting this state in
-capture result.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PASSIVE_FOCUSED</span>
-                    <span class="entry_type_enum_notes"><p>AF currently believes it is in focus,<wbr/> but may
-restart scanning at any time.<wbr/></p>
-<p>Only used by CONTINUOUS_<wbr/>* AF modes.<wbr/> This is a transient
-state,<wbr/> the camera device may skip reporting this state in
-capture result.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ACTIVE_SCAN</span>
-                    <span class="entry_type_enum_notes"><p>AF is performing an AF scan because it was
-triggered by AF trigger.<wbr/></p>
-<p>Only used by AUTO or MACRO AF modes.<wbr/> This is a transient
-state,<wbr/> the camera device may skip reporting this state in
-capture result.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FOCUSED_LOCKED</span>
-                    <span class="entry_type_enum_notes"><p>AF believes it is focused correctly and has locked
-focus.<wbr/></p>
-<p>This state is reached only after an explicit START AF trigger has been
-sent (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>),<wbr/> when good focus has been obtained.<wbr/></p>
-<p>The lens will remain stationary until the AF mode (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>) is changed or
-a new AF trigger is sent to the camera device (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>).<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">NOT_FOCUSED_LOCKED</span>
-                    <span class="entry_type_enum_notes"><p>AF has failed to focus successfully and has locked
-focus.<wbr/></p>
-<p>This state is reached only after an explicit START AF trigger has been
-sent (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>),<wbr/> when good focus cannot be obtained.<wbr/></p>
-<p>The lens will remain stationary until the AF mode (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>) is changed or
-a new AF trigger is sent to the camera device (<a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a>).<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PASSIVE_UNFOCUSED</span>
-                    <span class="entry_type_enum_notes"><p>AF finished a passive scan without finding focus,<wbr/>
-and may restart scanning at any time.<wbr/></p>
-<p>Only used by CONTINUOUS_<wbr/>* AF modes.<wbr/> This is a transient state,<wbr/> the camera
-device may skip reporting this state in capture result.<wbr/></p>
-<p>LEGACY camera devices do not support this state.<wbr/> When a passive
-scan has finished,<wbr/> it will always go to PASSIVE_<wbr/>FOCUSED.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Current state of auto-focus (AF) algorithm.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Switching between or enabling AF modes (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>) always
-resets the AF state to INACTIVE.<wbr/> Similarly,<wbr/> switching between <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>,<wbr/>
-or <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> if <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code> resets all
-the algorithm states to INACTIVE.<wbr/></p>
-<p>The camera device can do several state transitions between two results,<wbr/> if it is
-allowed by the state transition table.<wbr/> For example: INACTIVE may never actually be
-seen in a result.<wbr/></p>
-<p>The state in the result is the state for this image (in sync with this image): if
-AF state becomes FOCUSED,<wbr/> then the image data associated with this result should
-be sharp.<wbr/></p>
-<p>Below are state transition tables for different AF modes.<wbr/></p>
-<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>OFF or AF_<wbr/>MODE_<wbr/>EDOF:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center"></td>
-<td align="center">INACTIVE</td>
-<td align="center">Never changes</td>
-</tr>
-</tbody>
-</table>
-<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>AUTO or AF_<wbr/>MODE_<wbr/>MACRO:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">ACTIVE_<wbr/>SCAN</td>
-<td align="center">Start AF sweep,<wbr/> Lens now moving</td>
-</tr>
-<tr>
-<td align="center">ACTIVE_<wbr/>SCAN</td>
-<td align="center">AF sweep done</td>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Focused,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">ACTIVE_<wbr/>SCAN</td>
-<td align="center">AF sweep done</td>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Not focused,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">ACTIVE_<wbr/>SCAN</td>
-<td align="center">AF_<wbr/>CANCEL</td>
-<td align="center">INACTIVE</td>
-<td align="center">Cancel/<wbr/>reset AF,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>CANCEL</td>
-<td align="center">INACTIVE</td>
-<td align="center">Cancel/<wbr/>reset AF</td>
-</tr>
-<tr>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">ACTIVE_<wbr/>SCAN</td>
-<td align="center">Start new sweep,<wbr/> Lens now moving</td>
-</tr>
-<tr>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>CANCEL</td>
-<td align="center">INACTIVE</td>
-<td align="center">Cancel/<wbr/>reset AF</td>
-</tr>
-<tr>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">ACTIVE_<wbr/>SCAN</td>
-<td align="center">Start new sweep,<wbr/> Lens now moving</td>
-</tr>
-<tr>
-<td align="center">Any state</td>
-<td align="center">Mode change</td>
-<td align="center">INACTIVE</td>
-<td align="center"></td>
-</tr>
-</tbody>
-</table>
-<p>For the above table,<wbr/> the camera device may skip reporting any state changes that happen
-without application intervention (i.<wbr/>e.<wbr/> mode switch,<wbr/> trigger,<wbr/> locking).<wbr/> Any state that
-can be skipped in that manner is called a transient state.<wbr/></p>
-<p>For example,<wbr/> for these AF modes (AF_<wbr/>MODE_<wbr/>AUTO and AF_<wbr/>MODE_<wbr/>MACRO),<wbr/> in addition to the
-state transitions listed in above table,<wbr/> it is also legal for the camera device to skip
-one or more transient states between two results.<wbr/> See below table for examples:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Focus is already good or good after a scan,<wbr/> lens is now locked.<wbr/></td>
-</tr>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Focus failed after a scan,<wbr/> lens is now locked.<wbr/></td>
-</tr>
-<tr>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Focus is already good or good after a scan,<wbr/> lens is now locked.<wbr/></td>
-</tr>
-<tr>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Focus is good after a scan,<wbr/> lens is not locked.<wbr/></td>
-</tr>
-</tbody>
-</table>
-<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>CONTINUOUS_<wbr/>VIDEO:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">Camera device initiates new scan</td>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">Start AF scan,<wbr/> Lens now moving</td>
-</tr>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF state query,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">Camera device completes current scan</td>
-<td align="center">PASSIVE_<wbr/>FOCUSED</td>
-<td align="center">End AF scan,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">Camera device fails current scan</td>
-<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
-<td align="center">End AF scan,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Immediate transition,<wbr/> if focus is good.<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Immediate transition,<wbr/> if focus is bad.<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">AF_<wbr/>CANCEL</td>
-<td align="center">INACTIVE</td>
-<td align="center">Reset lens position,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>FOCUSED</td>
-<td align="center">Camera device initiates new scan</td>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">Start AF scan,<wbr/> Lens now moving</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
-<td align="center">Camera device initiates new scan</td>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">Start AF scan,<wbr/> Lens now moving</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>FOCUSED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Immediate transition,<wbr/> lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Immediate transition,<wbr/> lens now locked</td>
-</tr>
-<tr>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">No effect</td>
-</tr>
-<tr>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>CANCEL</td>
-<td align="center">INACTIVE</td>
-<td align="center">Restart AF scan</td>
-</tr>
-<tr>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">No effect</td>
-</tr>
-<tr>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>CANCEL</td>
-<td align="center">INACTIVE</td>
-<td align="center">Restart AF scan</td>
-</tr>
-</tbody>
-</table>
-<p>When <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> is AF_<wbr/>MODE_<wbr/>CONTINUOUS_<wbr/>PICTURE:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">Camera device initiates new scan</td>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">Start AF scan,<wbr/> Lens now moving</td>
-</tr>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF state query,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">Camera device completes current scan</td>
-<td align="center">PASSIVE_<wbr/>FOCUSED</td>
-<td align="center">End AF scan,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">Camera device fails current scan</td>
-<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
-<td align="center">End AF scan,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Eventual transition once the focus is good.<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Eventual transition if cannot find focus.<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">AF_<wbr/>CANCEL</td>
-<td align="center">INACTIVE</td>
-<td align="center">Reset lens position,<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>FOCUSED</td>
-<td align="center">Camera device initiates new scan</td>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">Start AF scan,<wbr/> Lens now moving</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
-<td align="center">Camera device initiates new scan</td>
-<td align="center">PASSIVE_<wbr/>SCAN</td>
-<td align="center">Start AF scan,<wbr/> Lens now moving</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>FOCUSED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Immediate trans.<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">PASSIVE_<wbr/>UNFOCUSED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">Immediate trans.<wbr/> Lens now locked</td>
-</tr>
-<tr>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">No effect</td>
-</tr>
-<tr>
-<td align="center">FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>CANCEL</td>
-<td align="center">INACTIVE</td>
-<td align="center">Restart AF scan</td>
-</tr>
-<tr>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>TRIGGER</td>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">No effect</td>
-</tr>
-<tr>
-<td align="center">NOT_<wbr/>FOCUSED_<wbr/>LOCKED</td>
-<td align="center">AF_<wbr/>CANCEL</td>
-<td align="center">INACTIVE</td>
-<td align="center">Restart AF scan</td>
-</tr>
-</tbody>
-</table>
-<p>When switch between AF_<wbr/>MODE_<wbr/>CONTINUOUS_<wbr/>* (CAF modes) and AF_<wbr/>MODE_<wbr/>AUTO/<wbr/>AF_<wbr/>MODE_<wbr/>MACRO
-(AUTO modes),<wbr/> the initial INACTIVE or PASSIVE_<wbr/>SCAN states may be skipped by the
-camera device.<wbr/> When a trigger is included in a mode switch request,<wbr/> the trigger
-will be evaluated in the context of the new mode in the request.<wbr/>
-See below table for examples:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">any state</td>
-<td align="center">CAF--&gt;AUTO mode switch</td>
-<td align="center">INACTIVE</td>
-<td align="center">Mode switch without trigger,<wbr/> initial state must be INACTIVE</td>
-</tr>
-<tr>
-<td align="center">any state</td>
-<td align="center">CAF--&gt;AUTO mode switch with AF_<wbr/>TRIGGER</td>
-<td align="center">trigger-reachable states from INACTIVE</td>
-<td align="center">Mode switch with trigger,<wbr/> INACTIVE is skipped</td>
-</tr>
-<tr>
-<td align="center">any state</td>
-<td align="center">AUTO--&gt;CAF mode switch</td>
-<td align="center">passively reachable states from INACTIVE</td>
-<td align="center">Mode switch without trigger,<wbr/> passive transient state is skipped</td>
-</tr>
-</tbody>
-</table>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.afTriggerId">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>af<wbr/>Trigger<wbr/>Id
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The ID sent with the latest
-CAMERA2_<wbr/>TRIGGER_<wbr/>AUTOFOCUS call</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Must be 0 if no CAMERA2_<wbr/>TRIGGER_<wbr/>AUTOFOCUS trigger
-received yet by HAL.<wbr/> Always updated even if AF algorithm
-ignores the trigger</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.awbLock">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>awb<wbr/>Lock
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Auto-white balance lock is disabled; the AWB
-algorithm is free to update its parameters if in AUTO
-mode.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>Auto-white balance lock is enabled; the AWB
-algorithm will not update its parameters while the lock
-is active.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether auto-white balance (AWB) is currently locked to its
-latest calculated values.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to <code>true</code> (ON),<wbr/> the AWB algorithm is locked to its latest parameters,<wbr/>
-and will not change color balance settings until the lock is set to <code>false</code> (OFF).<wbr/></p>
-<p>Since the camera device has a pipeline of in-flight requests,<wbr/> the settings that
-get locked do not necessarily correspond to the settings that were present in the
-latest capture result received from the camera device,<wbr/> since additional captures
-and AWB updates may have occurred even before the result was sent out.<wbr/> If an
-application is switching between automatic and manual control and wishes to eliminate
-any flicker during the switch,<wbr/> the following procedure is recommended:</p>
-<ol>
-<li>Starting in auto-AWB mode:</li>
-<li>Lock AWB</li>
-<li>Wait for the first result to be output that has the AWB locked</li>
-<li>Copy AWB settings from that result into a request,<wbr/> set the request to manual AWB</li>
-<li>Submit the capture request,<wbr/> proceed to run manual AWB as desired.<wbr/></li>
-</ol>
-<p>Note that AWB lock is only meaningful when
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> is in the AUTO mode; in other modes,<wbr/>
-AWB is already fixed to a specific setting.<wbr/></p>
-<p>Some LEGACY devices may not support ON; the value is then overridden to OFF.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.awbMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>awb<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled.<wbr/></p>
-<p>The application-selected color transform matrix
-(<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>) and gains
-(<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>) are used by the camera
-device for manual white balance control.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">AUTO</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is active.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">INCANDESCENT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses incandescent light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>While the exact white balance transforms are up to the
-camera device,<wbr/> they will approximately match the CIE
-standard illuminant A.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FLUORESCENT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses fluorescent light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>While the exact white balance transforms are up to the
-camera device,<wbr/> they will approximately match the CIE
-standard illuminant F2.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">WARM_FLUORESCENT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses warm fluorescent light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>While the exact white balance transforms are up to the
-camera device,<wbr/> they will approximately match the CIE
-standard illuminant F4.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">DAYLIGHT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses daylight light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>While the exact white balance transforms are up to the
-camera device,<wbr/> they will approximately match the CIE
-standard illuminant D65.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CLOUDY_DAYLIGHT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses cloudy daylight light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">TWILIGHT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses twilight light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SHADE</span>
-                    <span class="entry_type_enum_notes"><p>The camera device's auto-white balance routine is disabled;
-the camera device uses shade light as the assumed scene
-illumination for white balance.<wbr/></p>
-<p>The application's values for <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>
-and <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> are ignored.<wbr/>
-For devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability,<wbr/> the
-values used by the camera device for the transform and gains
-will be available in the capture result for this request.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether auto-white balance (AWB) is currently setting the color
-transform fields,<wbr/> and what its illumination target
-is.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.awbAvailableModes">android.<wbr/>control.<wbr/>awb<wbr/>Available<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control is only effective if <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is AUTO.<wbr/></p>
-<p>When set to the ON mode,<wbr/> the camera device's auto-white balance
-routine is enabled,<wbr/> overriding the application's selected
-<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
-<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/> Note that when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>
-is OFF,<wbr/> the behavior of AWB is device dependent.<wbr/> It is recommened to
-also set AWB mode to OFF or lock AWB by using <a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> before
-setting AE mode to OFF.<wbr/></p>
-<p>When set to the OFF mode,<wbr/> the camera device's auto-white balance
-routine is disabled.<wbr/> The application manually controls the white
-balance by <a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/> <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a>
-and <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a>.<wbr/></p>
-<p>When set to any other modes,<wbr/> the camera device's auto-white
-balance routine is disabled.<wbr/> The camera device uses each
-particular illumination target for white balance
-adjustment.<wbr/> The application's values for
-<a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a>,<wbr/>
-<a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> and
-<a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> are ignored.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.awbRegions">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>awb<wbr/>Regions
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  5 x area_count
-                </span>
-              <span class="entry_type_visibility"> [public as meteringRectangle]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of metering areas to use for auto-white-balance illuminant
-estimation.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixel coordinates within android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
-            </td>
-
-            <td class="entry_range">
-              <p>Coordinates must be between <code>[(0,<wbr/>0),<wbr/> (width,<wbr/> height))</code> of
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Not available if <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a> is 0.<wbr/>
-Otherwise will always be present.<wbr/></p>
-<p>The maximum number of regions supported by the device is determined by the value
-of <a href="#static_android.control.maxRegionsAwb">android.<wbr/>control.<wbr/>max<wbr/>Regions<wbr/>Awb</a>.<wbr/></p>
-<p>The coordinate system is based on the active pixel array,<wbr/>
-with (0,<wbr/>0) being the top-left pixel in the active pixel array,<wbr/> and
-(<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>width - 1,<wbr/>
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>height - 1) being the
-bottom-right pixel in the active pixel array.<wbr/></p>
-<p>The weight must range from 0 to 1000,<wbr/> and represents a weight
-for every pixel in the area.<wbr/> This means that a large metering area
-with the same weight as a smaller area will have more effect in
-the metering result.<wbr/> Metering areas can partially overlap and the
-camera device will add the weights in the overlap region.<wbr/></p>
-<p>The weights are relative to weights of other white balance metering regions,<wbr/> so if
-only one region is used,<wbr/> all non-zero weights will have the same effect.<wbr/> A region with
-0 weight is ignored.<wbr/></p>
-<p>If all regions have 0 weight,<wbr/> then no specific metering area needs to be used by the
-camera device.<wbr/></p>
-<p>If the metering region is outside the used <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> returned in
-capture result metadata,<wbr/> the camera device will ignore the sections outside the crop
-region and output only the intersection rectangle as the metering region in the result
-metadata.<wbr/>  If the region is entirely outside the crop region,<wbr/> it will be ignored and
-not reported in the result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL level representation of MeteringRectangle[] is a
-int[5 * area_<wbr/>count].<wbr/>
-Every five elements represent a metering region of
-(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax,<wbr/> weight).<wbr/>
-The rectangle is defined to be inclusive on xmin and ymin,<wbr/> but
-exclusive on xmax and ymax.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.captureIntent">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>capture<wbr/>Intent
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">CUSTOM</span>
-                    <span class="entry_type_enum_notes"><p>The goal of this request doesn't fall into the other
-categories.<wbr/> The camera device will default to preview-like
-behavior.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PREVIEW</span>
-                    <span class="entry_type_enum_notes"><p>This request is for a preview-like use case.<wbr/></p>
-<p>The precapture trigger may be used to start off a metering
-w/<wbr/>flash sequence.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">STILL_CAPTURE</span>
-                    <span class="entry_type_enum_notes"><p>This request is for a still capture-type
-use case.<wbr/></p>
-<p>If the flash unit is under automatic control,<wbr/> it may fire as needed.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">VIDEO_RECORD</span>
-                    <span class="entry_type_enum_notes"><p>This request is for a video recording
-use case.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">VIDEO_SNAPSHOT</span>
-                    <span class="entry_type_enum_notes"><p>This request is for a video snapshot (still
-image while recording video) use case.<wbr/></p>
-<p>The camera device should take the highest-quality image
-possible (given the other settings) without disrupting the
-frame rate of video recording.<wbr/>  </p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
-                    <span class="entry_type_enum_notes"><p>This request is for a ZSL usecase; the
-application will stream full-resolution images and
-reprocess one or several later for a final
-capture.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MANUAL</span>
-                    <span class="entry_type_enum_notes"><p>This request is for manual capture use case where
-the applications want to directly control the capture parameters.<wbr/></p>
-<p>For example,<wbr/> the application may wish to manually control
-<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> etc.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Information to the camera device 3A (auto-exposure,<wbr/>
-auto-focus,<wbr/> auto-white balance) routines about the purpose
-of this capture,<wbr/> to help the camera device to decide optimal 3A
-strategy.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control (except for MANUAL) is only effective if
-<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> != OFF</code> and any 3A routine is active.<wbr/></p>
-<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG will be supported if <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>
-contains PRIVATE_<wbr/>REPROCESSING or YUV_<wbr/>REPROCESSING.<wbr/> MANUAL will be supported if
-<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains MANUAL_<wbr/>SENSOR.<wbr/> Other intent values are
-always supported.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.awbState">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>awb<wbr/>State
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">INACTIVE</span>
-                    <span class="entry_type_enum_notes"><p>AWB is not in auto mode,<wbr/> or has not yet started metering.<wbr/></p>
-<p>When a camera device is opened,<wbr/> it starts in this
-state.<wbr/> This is a transient state,<wbr/> the camera device may
-skip reporting this state in capture
-result.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SEARCHING</span>
-                    <span class="entry_type_enum_notes"><p>AWB doesn't yet have a good set of control
-values for the current scene.<wbr/></p>
-<p>This is a transient state,<wbr/> the camera device
-may skip reporting this state in capture result.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CONVERGED</span>
-                    <span class="entry_type_enum_notes"><p>AWB has a good set of control values for the
-current scene.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">LOCKED</span>
-                    <span class="entry_type_enum_notes"><p>AWB has been locked.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Current state of auto-white balance (AWB) algorithm.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Switching between or enabling AWB modes (<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>) always
-resets the AWB state to INACTIVE.<wbr/> Similarly,<wbr/> switching between <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a>,<wbr/>
-or <a href="#controls_android.control.sceneMode">android.<wbr/>control.<wbr/>scene<wbr/>Mode</a> if <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code> resets all
-the algorithm states to INACTIVE.<wbr/></p>
-<p>The camera device can do several state transitions between two results,<wbr/> if it is
-allowed by the state transition table.<wbr/> So INACTIVE may never actually be seen in
-a result.<wbr/></p>
-<p>The state in the result is the state for this image (in sync with this image): if
-AWB state becomes CONVERGED,<wbr/> then the image data associated with this result should
-be good to use.<wbr/></p>
-<p>Below are state transition tables for different AWB modes.<wbr/></p>
-<p>When <code><a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> != AWB_<wbr/>MODE_<wbr/>AUTO</code>:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center"></td>
-<td align="center">INACTIVE</td>
-<td align="center">Camera device auto white balance algorithm is disabled</td>
-</tr>
-</tbody>
-</table>
-<p>When <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> is AWB_<wbr/>MODE_<wbr/>AUTO:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">Camera device initiates AWB scan</td>
-<td align="center">SEARCHING</td>
-<td align="center">Values changing</td>
-</tr>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is ON</td>
-<td align="center">LOCKED</td>
-<td align="center">Values locked</td>
-</tr>
-<tr>
-<td align="center">SEARCHING</td>
-<td align="center">Camera device finishes AWB scan</td>
-<td align="center">CONVERGED</td>
-<td align="center">Good values,<wbr/> not changing</td>
-</tr>
-<tr>
-<td align="center">SEARCHING</td>
-<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is ON</td>
-<td align="center">LOCKED</td>
-<td align="center">Values locked</td>
-</tr>
-<tr>
-<td align="center">CONVERGED</td>
-<td align="center">Camera device initiates AWB scan</td>
-<td align="center">SEARCHING</td>
-<td align="center">Values changing</td>
-</tr>
-<tr>
-<td align="center">CONVERGED</td>
-<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is ON</td>
-<td align="center">LOCKED</td>
-<td align="center">Values locked</td>
-</tr>
-<tr>
-<td align="center">LOCKED</td>
-<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is OFF</td>
-<td align="center">SEARCHING</td>
-<td align="center">Values not good after unlock</td>
-</tr>
-</tbody>
-</table>
-<p>For the above table,<wbr/> the camera device may skip reporting any state changes that happen
-without application intervention (i.<wbr/>e.<wbr/> mode switch,<wbr/> trigger,<wbr/> locking).<wbr/> Any state that
-can be skipped in that manner is called a transient state.<wbr/></p>
-<p>For example,<wbr/> for this AWB mode (AWB_<wbr/>MODE_<wbr/>AUTO),<wbr/> in addition to the state transitions
-listed in above table,<wbr/> it is also legal for the camera device to skip one or more
-transient states between two results.<wbr/> See below table for examples:</p>
-<table>
-<thead>
-<tr>
-<th align="center">State</th>
-<th align="center">Transition Cause</th>
-<th align="center">New State</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">INACTIVE</td>
-<td align="center">Camera device finished AWB scan</td>
-<td align="center">CONVERGED</td>
-<td align="center">Values are already good,<wbr/> transient states are skipped by camera device.<wbr/></td>
-</tr>
-<tr>
-<td align="center">LOCKED</td>
-<td align="center"><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a> is OFF</td>
-<td align="center">CONVERGED</td>
-<td align="center">Values good after unlock,<wbr/> transient states are skipped by camera device.<wbr/></td>
-</tr>
-</tbody>
-</table>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.effectMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>effect<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No color effect will be applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MONO</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "monocolor" effect where the image is mapped into
-a single color.<wbr/></p>
-<p>This will typically be grayscale.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">NEGATIVE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "photo-negative" effect where the image's colors
-are inverted.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SOLARIZE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "solarisation" effect (Sabattier effect) where the
-image is wholly or partially reversed in
-tone.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SEPIA</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "sepia" effect where the image is mapped into warm
-gray,<wbr/> red,<wbr/> and brown tones.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">POSTERIZE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "posterization" effect where the image uses
-discrete regions of tone rather than a continuous
-gradient of tones.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">WHITEBOARD</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "whiteboard" effect where the image is typically displayed
-as regions of white,<wbr/> with black or grey details.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">BLACKBOARD</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>A "blackboard" effect where the image is typically displayed
-as regions of black,<wbr/> with white or grey details.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">AQUA</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>An "aqua" effect where a blue hue is added to the image.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A special color effect to apply.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.availableEffects">android.<wbr/>control.<wbr/>available<wbr/>Effects</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When this mode is set,<wbr/> a color effect will be applied
-to images produced by the camera device.<wbr/> The interpretation
-and implementation of these color effects is left to the
-implementor of the camera device,<wbr/> and should not be
-depended on to be consistent (or present) across all
-devices.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.mode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Full application control of pipeline.<wbr/></p>
-<p>All control by the device's metering and focusing (3A)
-routines is disabled,<wbr/> and no other settings in
-android.<wbr/>control.<wbr/>* have any effect,<wbr/> except that
-<a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> may be used by the camera
-device to select post-processing values for processing
-blocks that do not allow for manual control,<wbr/> or are not
-exposed by the camera API.<wbr/></p>
-<p>However,<wbr/> the camera device's 3A routines may continue to
-collect statistics and update their internal state so that
-when control is switched to AUTO mode,<wbr/> good control values
-can be immediately applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">AUTO</span>
-                    <span class="entry_type_enum_notes"><p>Use settings for each individual 3A routine.<wbr/></p>
-<p>Manual control of capture parameters is disabled.<wbr/> All
-controls in android.<wbr/>control.<wbr/>* besides sceneMode take
-effect.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">USE_SCENE_MODE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Use a specific scene mode.<wbr/></p>
-<p>Enabling this disables control.<wbr/>aeMode,<wbr/> control.<wbr/>awbMode and
-control.<wbr/>afMode controls; the camera device will ignore
-those settings while USE_<wbr/>SCENE_<wbr/>MODE is active (except for
-FACE_<wbr/>PRIORITY scene mode).<wbr/> Other control entries are still active.<wbr/>
-This setting can only be used if scene mode is supported (i.<wbr/>e.<wbr/>
-<a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a>
-contain some modes other than DISABLED).<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">OFF_KEEP_STATE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Same as OFF mode,<wbr/> except that this capture will not be
-used by camera device background auto-exposure,<wbr/> auto-white balance and
-auto-focus algorithms (3A) to update their statistics.<wbr/></p>
-<p>Specifically,<wbr/> the 3A routines are locked to the last
-values set from a request with AUTO,<wbr/> OFF,<wbr/> or
-USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> and any statistics or state updates
-collected from manual captures with OFF_<wbr/>KEEP_<wbr/>STATE will be
-discarded by the camera device.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Overall mode of 3A (auto-exposure,<wbr/> auto-white-balance,<wbr/> auto-focus) control
-routines.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.availableModes">android.<wbr/>control.<wbr/>available<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is a top-level 3A control switch.<wbr/> When set to OFF,<wbr/> all 3A control
-by the camera device is disabled.<wbr/> The application must set the fields for
-capture parameters itself.<wbr/></p>
-<p>When set to AUTO,<wbr/> the individual algorithm controls in
-android.<wbr/>control.<wbr/>* are in effect,<wbr/> such as <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>.<wbr/></p>
-<p>When set to USE_<wbr/>SCENE_<wbr/>MODE,<wbr/> the individual controls in
-android.<wbr/>control.<wbr/>* are mostly disabled,<wbr/> and the camera device implements
-one of the scene mode settings (such as ACTION,<wbr/> SUNSET,<wbr/> or PARTY)
-as it wishes.<wbr/> The camera device scene mode 3A settings are provided by
-<a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">capture results</a>.<wbr/></p>
-<p>When set to OFF_<wbr/>KEEP_<wbr/>STATE,<wbr/> it is similar to OFF mode,<wbr/> the only difference
-is that this frame will not be used by camera device background 3A statistics
-update,<wbr/> as if this frame is never captured.<wbr/> This mode can be used in the scenario
-where the application doesn't want a 3A manual control capture to affect
-the subsequent auto 3A capture results.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.sceneMode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>control.<wbr/>scene<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">DISABLED</span>
-                    <span class="entry_type_enum_value">0</span>
-                    <span class="entry_type_enum_notes"><p>Indicates that no scene modes are set for a given capture request.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FACE_PRIORITY</span>
-                    <span class="entry_type_enum_notes"><p>If face detection support exists,<wbr/> use face
-detection data for auto-focus,<wbr/> auto-white balance,<wbr/> and
-auto-exposure routines.<wbr/></p>
-<p>If face detection statistics are disabled
-(i.<wbr/>e.<wbr/> <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> is set to OFF),<wbr/>
-this should still operate correctly (but will not return
-face detection statistics to the framework).<wbr/></p>
-<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
-remain active when FACE_<wbr/>PRIORITY is set.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ACTION</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving objects.<wbr/></p>
-<p>Similar to SPORTS.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PORTRAIT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for still photos of people.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">LANDSCAPE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for photos of distant macroscopic objects.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">NIGHT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for low-light settings.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">NIGHT_PORTRAIT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for still photos of people in low-light
-settings.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">THEATRE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings where flash must
-remain off.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">BEACH</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor beach settings.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SNOW</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for bright,<wbr/> outdoor settings containing snow.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SUNSET</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for scenes of the setting sun.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">STEADYPHOTO</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized to avoid blurry photos due to small amounts of
-device motion (for example: due to hand shake).<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FIREWORKS</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for nighttime photos of fireworks.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SPORTS</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for photos of quickly moving people.<wbr/></p>
-<p>Similar to ACTION.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PARTY</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for dim,<wbr/> indoor settings with multiple moving
-people.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CANDLELIGHT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for dim settings where the main light source
-is a flame.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">BARCODE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optimized for accurately capturing a photo of barcode
-for use by camera applications that wish to read the
-barcode value.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_SPEED_VIDEO</span>
-                    <span class="entry_type_enum_deprecated">[deprecated]</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>This is deprecated,<wbr/> please use <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>
-and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a>
-for high speed video recording.<wbr/></p>
-<p>Optimized for high speed video recording (frame rate &gt;=60fps) use case.<wbr/></p>
-<p>The supported high speed video sizes and fps ranges are specified in
-<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> To get desired
-output frame rates,<wbr/> the application is only allowed to select video size
-and fps range combinations listed in this static metadata.<wbr/> The fps range
-can be control via <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a>.<wbr/></p>
-<p>In this mode,<wbr/> the camera device will override aeMode,<wbr/> awbMode,<wbr/> and afMode to
-ON,<wbr/> ON,<wbr/> and CONTINUOUS_<wbr/>VIDEO,<wbr/> respectively.<wbr/> All post-processing block mode
-controls will be overridden to be FAST.<wbr/> Therefore,<wbr/> no manual control of capture
-and post-processing parameters is possible.<wbr/> All other controls operate the
-same as when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == AUTO.<wbr/> This means that all other
-android.<wbr/>control.<wbr/>* fields continue to work,<wbr/> such as</p>
-<ul>
-<li><a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a></li>
-<li><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a></li>
-<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li>
-<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li>
-<li><a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></li>
-<li><a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a></li>
-<li><a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a></li>
-<li><a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a></li>
-<li><a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a></li>
-<li><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a></li>
-</ul>
-<p>Outside of android.<wbr/>control.<wbr/>*,<wbr/> the following controls will work:</p>
-<ul>
-<li><a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> (automatic flash for still capture will not work since aeMode is ON)</li>
-<li><a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> (if it is supported)</li>
-<li><a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a></li>
-<li><a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a></li>
-</ul>
-<p>For high speed recording use case,<wbr/> the actual maximum supported frame rate may
-be lower than what camera can output,<wbr/> depending on the destination Surfaces for
-the image data.<wbr/> For example,<wbr/> if the destination surface is from video encoder,<wbr/>
-the application need check if the video encoder is capable of supporting the
-high frame rate for a given video size,<wbr/> or it will end up with lower recording
-frame rate.<wbr/> If the destination surface is from preview window,<wbr/> the preview frame
-rate will be bounded by the screen refresh rate.<wbr/></p>
-<p>The camera device will only support up to 2 output high speed streams
-(processed non-stalling format defined in <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>)
-in this mode.<wbr/> This control will be effective only if all of below conditions are true:</p>
-<ul>
-<li>The application created no more than maxNumHighSpeedStreams processed non-stalling
-format output streams,<wbr/> where maxNumHighSpeedStreams is calculated as
-min(2,<wbr/> <a href="#static_android.request.maxNumOutputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams</a>[Processed (but not-stalling)]).<wbr/></li>
-<li>The stream sizes are selected from the sizes reported by
-<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/></li>
-<li>No processed non-stalling or raw streams are configured.<wbr/></li>
-</ul>
-<p>When above conditions are NOT satistied,<wbr/> the controls of this mode and
-<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> will be ignored by the camera device,<wbr/>
-the camera device will fall back to <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> <code>==</code> AUTO,<wbr/>
-and the returned capture result metadata will give the fps range choosen
-by the camera device.<wbr/></p>
-<p>Switching into or out of this mode may trigger some camera ISP/<wbr/>sensor
-reconfigurations,<wbr/> which may introduce extra latency.<wbr/> It is recommended that
-the application avoids unnecessary scene mode switch as much as possible.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HDR</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Turn on a device-specific high dynamic range (HDR) mode.<wbr/></p>
-<p>In this scene mode,<wbr/> the camera device captures images
-that keep a larger range of scene illumination levels
-visible in the final image.<wbr/> For example,<wbr/> when taking a
-picture of a object in front of a bright window,<wbr/> both
-the object and the scene through the window may be
-visible when using HDR mode,<wbr/> while in normal AUTO mode,<wbr/>
-one or the other may be poorly exposed.<wbr/> As a tradeoff,<wbr/>
-HDR mode generally takes much longer to capture a single
-image,<wbr/> has no user control,<wbr/> and may have other artifacts
-depending on the HDR method used.<wbr/></p>
-<p>Therefore,<wbr/> HDR captures operate at a much slower rate
-than regular captures.<wbr/></p>
-<p>In this mode,<wbr/> on LIMITED or FULL devices,<wbr/> when a request
-is made with a <a href="#controls_android.control.captureIntent">android.<wbr/>control.<wbr/>capture<wbr/>Intent</a> of
-STILL_<wbr/>CAPTURE,<wbr/> the camera device will capture an image
-using a high dynamic range capture technique.<wbr/>  On LEGACY
-devices,<wbr/> captures that target a JPEG-format output will
-be captured with HDR,<wbr/> and the capture intent is not
-relevant.<wbr/></p>
-<p>The HDR capture may involve the device capturing a burst
-of images internally and combining them into one,<wbr/> or it
-may involve the device using specialized high dynamic
-range capture hardware.<wbr/> In all cases,<wbr/> a single image is
-produced in response to a capture request submitted
-while in HDR mode.<wbr/></p>
-<p>Since substantial post-processing is generally needed to
-produce an HDR image,<wbr/> only YUV,<wbr/> PRIVATE,<wbr/> and JPEG
-outputs are supported for LIMITED/<wbr/>FULL device HDR
-captures,<wbr/> and only JPEG outputs are supported for LEGACY
-HDR captures.<wbr/> Using a RAW output for HDR capture is not
-supported.<wbr/></p>
-<p>Some devices may also support always-on HDR,<wbr/> which
-applies HDR processing at full frame rate.<wbr/>  For these
-devices,<wbr/> intents other than STILL_<wbr/>CAPTURE will also
-produce an HDR output with no frame rate impact compared
-to normal operation,<wbr/> though the quality may be lower
-than for STILL_<wbr/>CAPTURE intents.<wbr/></p>
-<p>If SCENE_<wbr/>MODE_<wbr/>HDR is used with unsupported output types
-or capture intents,<wbr/> the images captured will be as if
-the SCENE_<wbr/>MODE was not enabled at all.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FACE_PRIORITY_LOW_LIGHT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_hidden">[hidden]</span>
-                    <span class="entry_type_enum_notes"><p>Same as FACE_<wbr/>PRIORITY scene mode,<wbr/> except that the camera
-device will choose higher sensitivity values (<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>)
-under low light conditions.<wbr/></p>
-<p>The camera device may be tuned to expose the images in a reduced
-sensitivity range to produce the best quality images.<wbr/> For example,<wbr/>
-if the <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> gives range of [100,<wbr/> 1600],<wbr/>
-the camera device auto-exposure routine tuning process may limit the actual
-exposure sensitivity range to [100,<wbr/> 1200] to ensure that the noise level isn't
-exessive in order to preserve the image quality.<wbr/> Under this situation,<wbr/> the image under
-low light may be under-exposed when the sensor max exposure time (bounded by the
-<a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a> when <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of the
-ON_<wbr/>* modes) and effective max sensitivity are reached.<wbr/> This scene mode allows the
-camera device auto-exposure routine to increase the sensitivity up to the max
-sensitivity specified by <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a> when the scene is too
-dark and the max exposure time is reached.<wbr/> The captured images may be noisier
-compared with the images captured in normal FACE_<wbr/>PRIORITY mode; therefore,<wbr/> it is
-recommended that the application only use this scene mode when it is capable of
-reducing the noise level of the captured images.<wbr/></p>
-<p>Unlike the other scene modes,<wbr/> <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
-remain active when FACE_<wbr/>PRIORITY_<wbr/>LOW_<wbr/>LIGHT is set.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">DEVICE_CUSTOM_START</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_hidden">[hidden]</span>
-                    <span class="entry_type_enum_value">100</span>
-                    <span class="entry_type_enum_notes"><p>Scene mode values within the range of
-<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific
-customized scene modes.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">DEVICE_CUSTOM_END</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_hidden">[hidden]</span>
-                    <span class="entry_type_enum_value">127</span>
-                    <span class="entry_type_enum_notes"><p>Scene mode values within the range of
-<code>[DEVICE_<wbr/>CUSTOM_<wbr/>START,<wbr/> DEVICE_<wbr/>CUSTOM_<wbr/>END]</code> are reserved for device specific
-customized scene modes.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Control for which scene mode is currently active.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Scene modes are custom camera modes optimized for a certain set of conditions and
-capture settings.<wbr/></p>
-<p>This is the mode that that is active when
-<code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == USE_<wbr/>SCENE_<wbr/>MODE</code>.<wbr/> Aside from FACE_<wbr/>PRIORITY,<wbr/> these modes will
-disable <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>
-while in use.<wbr/></p>
-<p>The interpretation and implementation of these scene modes is left
-to the implementor of the camera device.<wbr/> Their behavior will not be
-consistent across all devices,<wbr/> and any given device may only implement
-a subset of these modes.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL implementations that include scene modes are expected to provide
-the per-scene settings to use for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/>
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>,<wbr/> and <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> in
-<a href="#static_android.control.sceneModeOverrides">android.<wbr/>control.<wbr/>scene<wbr/>Mode<wbr/>Overrides</a>.<wbr/></p>
-<p>For HIGH_<wbr/>SPEED_<wbr/>VIDEO mode,<wbr/> if it is included in <a href="#static_android.control.availableSceneModes">android.<wbr/>control.<wbr/>available<wbr/>Scene<wbr/>Modes</a>,<wbr/>
-the HAL must list supported video size and fps range in
-<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a>.<wbr/> For a given size,<wbr/> e.<wbr/>g.<wbr/>
-1280x720,<wbr/> if the HAL has two different sensor configurations for normal streaming
-mode and high speed streaming,<wbr/> when this scene mode is set/<wbr/>reset in a sequence of capture
-requests,<wbr/> the HAL may have to switch between different sensor modes.<wbr/>
-This mode is deprecated in HAL3.<wbr/>3,<wbr/> to support high speed video recording,<wbr/> please implement
-<a href="#static_android.control.availableHighSpeedVideoConfigurations">android.<wbr/>control.<wbr/>available<wbr/>High<wbr/>Speed<wbr/>Video<wbr/>Configurations</a> and CONSTRAINED_<wbr/>HIGH_<wbr/>SPEED_<wbr/>VIDEO
-capbility defined in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.videoStabilizationMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Video stabilization is disabled.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>Video stabilization is enabled.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether video stabilization is
-active.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Video stabilization automatically warps images from
-the camera in order to stabilize motion between consecutive frames.<wbr/></p>
-<p>If enabled,<wbr/> video stabilization can modify the
-<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a> to keep the video stream stabilized.<wbr/></p>
-<p>Switching between different video stabilization modes may take several
-frames to initialize,<wbr/> the camera device will report the current mode
-in capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/>
-the video stabilization modes in the first several capture results may
-still be "OFF",<wbr/> and it will become "ON" when the initialization is
-done.<wbr/></p>
-<p>In addition,<wbr/> not all recording sizes or frame rates may be supported for
-stabilization by a device that reports stabilization support.<wbr/> It is guaranteed
-that an output targeting a MediaRecorder or MediaCodec will be stabilized if
-the recording resolution is less than or equal to 1920 x 1080 (width less than
-or equal to 1920,<wbr/> height less than or equal to 1080),<wbr/> and the recording
-frame rate is less than or equal to 30fps.<wbr/>  At other sizes,<wbr/> the CaptureResult
-<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a> field will return
-OFF if the recording output is not stabilized,<wbr/> or if there are no output
-Surface types that can be stabilized.<wbr/></p>
-<p>If a camera device supports both this mode and OIS
-(<a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may
-produce undesirable interaction,<wbr/> so it is recommended not to enable
-both at the same time.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.control.postRawSensitivityBoost">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The amount of additional sensitivity boost applied to output images
-after RAW sensor data is captured.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              ISO arithmetic units,<wbr/> the same as android.<wbr/>sensor.<wbr/>sensitivity
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.control.postRawSensitivityBoostRange">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost<wbr/>Range</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Some camera devices support additional digital sensitivity boosting in the
-camera processing pipeline after sensor RAW image is captured.<wbr/>
-Such a boost will be applied to YUV/<wbr/>JPEG format output images but will not
-have effect on RAW output formats like RAW_<wbr/>SENSOR,<wbr/> RAW10,<wbr/> RAW12 or RAW_<wbr/>OPAQUE.<wbr/></p>
-<p>This key will be <code>null</code> for devices that do not support any RAW format
-outputs.<wbr/> For devices that do support RAW format outputs,<wbr/> this key will always
-present,<wbr/> and if a device does not support post RAW sensitivity boost,<wbr/> it will
-list <code>100</code> in this key.<wbr/></p>
-<p>If the camera device cannot apply the exact boost requested,<wbr/> it will reduce the
-boost to the nearest supported value.<wbr/>
-The final boost value used will be available in the output capture result.<wbr/></p>
-<p>For devices that support post RAW sensitivity boost,<wbr/> the YUV/<wbr/>JPEG output images
-of such device will have the total sensitivity of
-<code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> * <a href="#controls_android.control.postRawSensitivityBoost">android.<wbr/>control.<wbr/>post<wbr/>Raw<wbr/>Sensitivity<wbr/>Boost</a> /<wbr/> 100</code>
-The sensitivity of RAW format images will always be <code><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></code></p>
-<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
-OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_demosaic" class="section">demosaic</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.demosaic.mode">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>demosaic.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Minimal or no slowdown of frame rate compared to
-Bayer RAW output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>Improved processing quality but the frame rate might be slowed down
-relative to raw output.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Controls the quality of the demosaicing
-processing.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_edge" class="section">edge</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.edge.mode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>edge.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No edge enhancement is applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Apply edge enhancement at a quality level that does not slow down frame rate
-relative to sensor output.<wbr/> It may be the same as OFF if edge enhancement will
-slow down frame rate relative to sensor.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>Apply high-quality edge enhancement,<wbr/> at a cost of possibly reduced output frame rate.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Edge enhancement is applied at different levels for different output streams,<wbr/>
-based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have
-edge enhancement applied,<wbr/> while higher-resolution streams have no edge enhancement
-applied.<wbr/> The level of edge enhancement for low-resolution streams is tuned so that
-frame rate is not impacted,<wbr/> and the quality is equal to or better than FAST (since it
-is only applied to lower-resolution outputs,<wbr/> quality may improve from FAST).<wbr/></p>
-<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
-with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures
-high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is
-produced via reprocessing when a user takes a picture.<wbr/>  For such a use case,<wbr/> the
-high-resolution buffers must not have edge enhancement applied to maximize efficiency of
-preview and to avoid double-applying enhancement when reprocessed,<wbr/> while low-resolution
-buffers (used for recording or preview,<wbr/> generally) need edge enhancement applied for
-reasonable preview quality.<wbr/></p>
-<p>This mode is guaranteed to be supported by devices that support either the
-YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities
-(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will
-be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operation mode for edge
-enhancement.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Edge enhancement improves sharpness and details in the captured image.<wbr/> OFF means
-no enhancement will be applied by the camera device.<wbr/></p>
-<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined enhancement
-will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the
-camera device will use the highest-quality enhancement algorithms,<wbr/>
-even if it slows down capture rate.<wbr/> FAST means the camera device will
-not slow down capture rate when applying edge enhancement.<wbr/> FAST may be the same as OFF if
-edge enhancement will slow down capture rate.<wbr/> Every output stream will have a similar
-amount of enhancement applied.<wbr/></p>
-<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular
-buffer of high-resolution images during preview and reprocess image(s) from that buffer
-into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies
-edge enhancement to low-resolution streams (below maximum recording resolution) to
-maximize preview quality,<wbr/> but does not apply edge enhancement to high-resolution streams,<wbr/>
-since those will be reprocessed later if necessary.<wbr/></p>
-<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera
-device will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV-domain edge enhancement,<wbr/> respectively.<wbr/>
-The camera device may adjust its internal edge enhancement parameters for best
-image quality based on the <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a>,<wbr/> if it is set.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to
-adjust the internal edge enhancement reduction parameters appropriately to get the best
-quality images.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.edge.strength">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>edge.<wbr/>strength
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Control the amount of edge enhancement
-applied to the images</p>
-            </td>
-
-            <td class="entry_units">
-              1-10; 10 is maximum sharpening
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.edge.availableEdgeModes">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of edge enhancement modes for <a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a> that are supported by this camera
-device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Full-capability camera devices must always support OFF; camera devices that support
-YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING will list ZERO_<wbr/>SHUTTER_<wbr/>LAG; all devices will
-list FAST.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if edge enhancement control is available
-on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
-That is,<wbr/> if the highest quality implementation on the camera device does not slow down
-capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.edge.mode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>edge.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No edge enhancement is applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Apply edge enhancement at a quality level that does not slow down frame rate
-relative to sensor output.<wbr/> It may be the same as OFF if edge enhancement will
-slow down frame rate relative to sensor.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>Apply high-quality edge enhancement,<wbr/> at a cost of possibly reduced output frame rate.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Edge enhancement is applied at different levels for different output streams,<wbr/>
-based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have
-edge enhancement applied,<wbr/> while higher-resolution streams have no edge enhancement
-applied.<wbr/> The level of edge enhancement for low-resolution streams is tuned so that
-frame rate is not impacted,<wbr/> and the quality is equal to or better than FAST (since it
-is only applied to lower-resolution outputs,<wbr/> quality may improve from FAST).<wbr/></p>
-<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
-with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures
-high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is
-produced via reprocessing when a user takes a picture.<wbr/>  For such a use case,<wbr/> the
-high-resolution buffers must not have edge enhancement applied to maximize efficiency of
-preview and to avoid double-applying enhancement when reprocessed,<wbr/> while low-resolution
-buffers (used for recording or preview,<wbr/> generally) need edge enhancement applied for
-reasonable preview quality.<wbr/></p>
-<p>This mode is guaranteed to be supported by devices that support either the
-YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities
-(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will
-be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operation mode for edge
-enhancement.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Edge enhancement improves sharpness and details in the captured image.<wbr/> OFF means
-no enhancement will be applied by the camera device.<wbr/></p>
-<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined enhancement
-will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the
-camera device will use the highest-quality enhancement algorithms,<wbr/>
-even if it slows down capture rate.<wbr/> FAST means the camera device will
-not slow down capture rate when applying edge enhancement.<wbr/> FAST may be the same as OFF if
-edge enhancement will slow down capture rate.<wbr/> Every output stream will have a similar
-amount of enhancement applied.<wbr/></p>
-<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular
-buffer of high-resolution images during preview and reprocess image(s) from that buffer
-into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies
-edge enhancement to low-resolution streams (below maximum recording resolution) to
-maximize preview quality,<wbr/> but does not apply edge enhancement to high-resolution streams,<wbr/>
-since those will be reprocessed later if necessary.<wbr/></p>
-<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera
-device will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV-domain edge enhancement,<wbr/> respectively.<wbr/>
-The camera device may adjust its internal edge enhancement parameters for best
-image quality based on the <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a>,<wbr/> if it is set.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to
-adjust the internal edge enhancement reduction parameters appropriately to get the best
-quality images.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_flash" class="section">flash</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.flash.firingPower">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>flash.<wbr/>firing<wbr/>Power
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Power for flash firing/<wbr/>torch</p>
-            </td>
-
-            <td class="entry_units">
-              10 is max power; 0 is no flash.<wbr/> Linear
-            </td>
-
-            <td class="entry_range">
-              <p>0 - 10</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Power for snapshot may use a different scale than
-for torch mode.<wbr/> Only one entry for torch mode will be
-used</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.flash.firingTime">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>flash.<wbr/>firing<wbr/>Time
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Firing time of flash relative to start of
-exposure</p>
-            </td>
-
-            <td class="entry_units">
-              nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p>0-(exposure time-flash duration)</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Clamped to (0,<wbr/> exposure time - flash
-duration).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.flash.mode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>flash.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Do not fire the flash for this capture.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SINGLE</span>
-                    <span class="entry_type_enum_notes"><p>If the flash is available and charged,<wbr/> fire flash
-for this capture.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">TORCH</span>
-                    <span class="entry_type_enum_notes"><p>Transition flash to continuously on.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired mode for for the camera device's flash control.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control is only effective when flash unit is available
-(<code><a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> == true</code>).<wbr/></p>
-<p>When this control is used,<wbr/> the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> must be set to ON or OFF.<wbr/>
-Otherwise,<wbr/> the camera device auto-exposure related flash control (ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/>
-ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> or ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE) will override this control.<wbr/></p>
-<p>When set to OFF,<wbr/> the camera device will not fire flash for this capture.<wbr/></p>
-<p>When set to SINGLE,<wbr/> the camera device will fire flash regardless of the camera
-device's auto-exposure routine's result.<wbr/> When used in still capture case,<wbr/> this
-control should be used along with auto-exposure (AE) precapture metering sequence
-(<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>),<wbr/> otherwise,<wbr/> the image may be incorrectly exposed.<wbr/></p>
-<p>When set to TORCH,<wbr/> the flash will be on continuously.<wbr/> This mode can be used
-for use cases such as preview,<wbr/> auto-focus assist,<wbr/> still capture,<wbr/> or video recording.<wbr/></p>
-<p>The flash status will be reported by <a href="#dynamic_android.flash.state">android.<wbr/>flash.<wbr/>state</a> in the capture result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-                
-            
-
-                
-          <tr class="entry" id="static_android.flash.info.available">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>flash.<wbr/>info.<wbr/>available
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">FALSE</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">TRUE</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether this camera device has a
-flash unit.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Will be <code>false</code> if no flash is available.<wbr/></p>
-<p>If there is no flash unit,<wbr/> none of the flash controls do
-anything.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.flash.info.chargeDuration">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>flash.<wbr/>info.<wbr/>charge<wbr/>Duration
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Time taken before flash can fire
-again</p>
-            </td>
-
-            <td class="entry_units">
-              nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p>0-1e9</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>1 second too long/<wbr/>too short for recharge? Should
-this be power-dependent?</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-        
-
-                
-          <tr class="entry" id="static_android.flash.colorTemperature">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>flash.<wbr/>color<wbr/>Temperature
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The x,<wbr/>y whitepoint of the
-flash</p>
-            </td>
-
-            <td class="entry_units">
-              pair of floats
-            </td>
-
-            <td class="entry_range">
-              <p>0-1 for both</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.flash.maxEnergy">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>flash.<wbr/>max<wbr/>Energy
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Max energy output of the flash for a full
-power single flash</p>
-            </td>
-
-            <td class="entry_units">
-              lumen-seconds
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.flash.firingPower">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>flash.<wbr/>firing<wbr/>Power
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Power for flash firing/<wbr/>torch</p>
-            </td>
-
-            <td class="entry_units">
-              10 is max power; 0 is no flash.<wbr/> Linear
-            </td>
-
-            <td class="entry_range">
-              <p>0 - 10</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Power for snapshot may use a different scale than
-for torch mode.<wbr/> Only one entry for torch mode will be
-used</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.flash.firingTime">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>flash.<wbr/>firing<wbr/>Time
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Firing time of flash relative to start of
-exposure</p>
-            </td>
-
-            <td class="entry_units">
-              nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p>0-(exposure time-flash duration)</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Clamped to (0,<wbr/> exposure time - flash
-duration).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.flash.mode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>flash.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Do not fire the flash for this capture.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SINGLE</span>
-                    <span class="entry_type_enum_notes"><p>If the flash is available and charged,<wbr/> fire flash
-for this capture.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">TORCH</span>
-                    <span class="entry_type_enum_notes"><p>Transition flash to continuously on.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired mode for for the camera device's flash control.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control is only effective when flash unit is available
-(<code><a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> == true</code>).<wbr/></p>
-<p>When this control is used,<wbr/> the <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> must be set to ON or OFF.<wbr/>
-Otherwise,<wbr/> the camera device auto-exposure related flash control (ON_<wbr/>AUTO_<wbr/>FLASH,<wbr/>
-ON_<wbr/>ALWAYS_<wbr/>FLASH,<wbr/> or ON_<wbr/>AUTO_<wbr/>FLASH_<wbr/>REDEYE) will override this control.<wbr/></p>
-<p>When set to OFF,<wbr/> the camera device will not fire flash for this capture.<wbr/></p>
-<p>When set to SINGLE,<wbr/> the camera device will fire flash regardless of the camera
-device's auto-exposure routine's result.<wbr/> When used in still capture case,<wbr/> this
-control should be used along with auto-exposure (AE) precapture metering sequence
-(<a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>),<wbr/> otherwise,<wbr/> the image may be incorrectly exposed.<wbr/></p>
-<p>When set to TORCH,<wbr/> the flash will be on continuously.<wbr/> This mode can be used
-for use cases such as preview,<wbr/> auto-focus assist,<wbr/> still capture,<wbr/> or video recording.<wbr/></p>
-<p>The flash status will be reported by <a href="#dynamic_android.flash.state">android.<wbr/>flash.<wbr/>state</a> in the capture result metadata.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.flash.state">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>flash.<wbr/>state
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">UNAVAILABLE</span>
-                    <span class="entry_type_enum_notes"><p>No flash on camera.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CHARGING</span>
-                    <span class="entry_type_enum_notes"><p>Flash is charging and cannot be fired.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">READY</span>
-                    <span class="entry_type_enum_notes"><p>Flash is ready to fire.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FIRED</span>
-                    <span class="entry_type_enum_notes"><p>Flash fired for this capture.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PARTIAL</span>
-                    <span class="entry_type_enum_notes"><p>Flash partially illuminated this frame.<wbr/></p>
-<p>This is usually due to the next or previous frame having
-the flash fire,<wbr/> and the flash spilling into this capture
-due to hardware limitations.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Current state of the flash
-unit.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When the camera device doesn't have flash unit
-(i.<wbr/>e.<wbr/> <code><a href="#static_android.flash.info.available">android.<wbr/>flash.<wbr/>info.<wbr/>available</a> == false</code>),<wbr/> this state will always be UNAVAILABLE.<wbr/>
-Other states indicate the current flash status.<wbr/></p>
-<p>In certain conditions,<wbr/> this will be available on LEGACY devices:</p>
-<ul>
-<li>Flash-less cameras always return UNAVAILABLE.<wbr/></li>
-<li>Using <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>==</code> ON_<wbr/>ALWAYS_<wbr/>FLASH
-   will always return FIRED.<wbr/></li>
-<li>Using <a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> <code>==</code> TORCH
-   will always return FIRED.<wbr/></li>
-</ul>
-<p>In all other conditions the state will not be available on
-LEGACY devices (i.<wbr/>e.<wbr/> it will be <code>null</code>).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_hotPixel" class="section">hotPixel</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.hotPixel.mode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>hot<wbr/>Pixel.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No hot pixel correction is applied.<wbr/></p>
-<p>The frame rate must not be reduced relative to sensor raw output
-for this option.<wbr/></p>
-<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Hot pixel correction is applied,<wbr/> without reducing frame
-rate relative to sensor raw output.<wbr/></p>
-<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>High-quality hot pixel correction is applied,<wbr/> at a cost
-of possibly reduced frame rate relative to sensor raw output.<wbr/></p>
-<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operational mode for hot pixel correction.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.hotPixel.availableHotPixelModes">android.<wbr/>hot<wbr/>Pixel.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Hotpixel correction interpolates out,<wbr/> or otherwise removes,<wbr/> pixels
-that do not accurately measure the incoming light (i.<wbr/>e.<wbr/> pixels that
-are stuck at an arbitrary value or are oversensitive).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.hotPixel.availableHotPixelModes">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>hot<wbr/>Pixel.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of hot pixel correction modes for <a href="#controls_android.hotPixel.mode">android.<wbr/>hot<wbr/>Pixel.<wbr/>mode</a> that are supported by this
-camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.hotPixel.mode">android.<wbr/>hot<wbr/>Pixel.<wbr/>mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>FULL mode camera devices will always support FAST.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>To avoid performance issues,<wbr/> there will be significantly fewer hot
-pixels than actual pixels on the camera sensor.<wbr/>
-HAL must support both FAST and HIGH_<wbr/>QUALITY if hot pixel correction control is available
-on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
-That is,<wbr/> if the highest quality implementation on the camera device does not slow down
-capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.hotPixel.mode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>hot<wbr/>Pixel.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No hot pixel correction is applied.<wbr/></p>
-<p>The frame rate must not be reduced relative to sensor raw output
-for this option.<wbr/></p>
-<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Hot pixel correction is applied,<wbr/> without reducing frame
-rate relative to sensor raw output.<wbr/></p>
-<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>High-quality hot pixel correction is applied,<wbr/> at a cost
-of possibly reduced frame rate relative to sensor raw output.<wbr/></p>
-<p>The hotpixel map may be returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operational mode for hot pixel correction.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.hotPixel.availableHotPixelModes">android.<wbr/>hot<wbr/>Pixel.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Hotpixel correction interpolates out,<wbr/> or otherwise removes,<wbr/> pixels
-that do not accurately measure the incoming light (i.<wbr/>e.<wbr/> pixels that
-are stuck at an arbitrary value or are oversensitive).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_jpeg" class="section">jpeg</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.jpeg.gpsLocation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>jpeg.<wbr/>gps<wbr/>Location
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [java_public as location]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A location object to use when generating image GPS metadata.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Setting a location object in a request will include the GPS coordinates of the location
-into any JPEG images captured based on the request.<wbr/> These coordinates can then be
-viewed by anyone who receives the JPEG image.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.jpeg.gpsCoordinates">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>jpeg.<wbr/>gps<wbr/>Coordinates
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">double</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">latitude,<wbr/> longitude,<wbr/> altitude.<wbr/> First two in degrees,<wbr/> the third in meters</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>GPS coordinates to include in output JPEG
-EXIF.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>(-180 - 180],<wbr/> [-90,<wbr/>90],<wbr/> [-inf,<wbr/> inf]</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.jpeg.gpsProcessingMethod">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>jpeg.<wbr/>gps<wbr/>Processing<wbr/>Method
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [ndk_public as string]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>32 characters describing GPS algorithm to
-include in EXIF.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              UTF-8 null-terminated string
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.jpeg.gpsTimestamp">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>jpeg.<wbr/>gps<wbr/>Timestamp
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Time GPS fix was made to include in
-EXIF.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              UTC in seconds since January 1,<wbr/> 1970
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.jpeg.orientation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>jpeg.<wbr/>orientation
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The orientation for a JPEG image.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Degrees in multiples of 90
-            </td>
-
-            <td class="entry_range">
-              <p>0,<wbr/> 90,<wbr/> 180,<wbr/> 270</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The clockwise rotation angle in degrees,<wbr/> relative to the orientation
-to the camera,<wbr/> that the JPEG picture needs to be rotated by,<wbr/> to be viewed
-upright.<wbr/></p>
-<p>Camera devices may either encode this value into the JPEG EXIF header,<wbr/> or
-rotate the image data to match this orientation.<wbr/> When the image data is rotated,<wbr/>
-the thumbnail data will also be rotated.<wbr/></p>
-<p>Note that this orientation is relative to the orientation of the camera sensor,<wbr/> given
-by <a href="#static_android.sensor.orientation">android.<wbr/>sensor.<wbr/>orientation</a>.<wbr/></p>
-<p>To translate from the device orientation given by the Android sensor APIs,<wbr/> the following
-sample code may be used:</p>
-<pre><code>private int getJpegOrientation(CameraCharacteristics c,<wbr/> int deviceOrientation) {
-    if (deviceOrientation == android.<wbr/>view.<wbr/>Orientation<wbr/>Event<wbr/>Listener.<wbr/>ORIENTATION_<wbr/>UNKNOWN) return 0;
-    int sensorOrientation = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>SENSOR_<wbr/>ORIENTATION);
-
-    //<wbr/> Round device orientation to a multiple of 90
-    deviceOrientation = (deviceOrientation + 45) /<wbr/> 90 * 90;
-
-    //<wbr/> Reverse device orientation for front-facing cameras
-    boolean facingFront = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING) == Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING_<wbr/>FRONT;
-    if (facingFront) deviceOrientation = -deviceOrientation;
-
-    //<wbr/> Calculate desired JPEG orientation relative to camera orientation to make
-    //<wbr/> the image upright relative to the device orientation
-    int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360;
-
-    return jpegOrientation;
-}
-</code></pre>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.jpeg.quality">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>jpeg.<wbr/>quality
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Compression quality of the final JPEG
-image.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>1-100; larger is higher quality</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>85-95 is typical usage range.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.jpeg.thumbnailQuality">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Quality
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Compression quality of JPEG
-thumbnail.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>1-100; larger is higher quality</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.jpeg.thumbnailSize">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as size]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Resolution of embedded JPEG thumbnail.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.jpeg.availableThumbnailSizes">android.<wbr/>jpeg.<wbr/>available<wbr/>Thumbnail<wbr/>Sizes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to (0,<wbr/> 0) value,<wbr/> the JPEG EXIF will not contain thumbnail,<wbr/>
-but the captured JPEG will still be a valid image.<wbr/></p>
-<p>For best results,<wbr/> when issuing a request for a JPEG image,<wbr/> the thumbnail size selected
-should have the same aspect ratio as the main JPEG output.<wbr/></p>
-<p>If the thumbnail image aspect ratio differs from the JPEG primary image aspect
-ratio,<wbr/> the camera device creates the thumbnail by cropping it from the primary image.<wbr/>
-For example,<wbr/> if the primary image has 4:3 aspect ratio,<wbr/> the thumbnail image has
-16:9 aspect ratio,<wbr/> the primary image will be cropped vertically (letterbox) to
-generate the thumbnail image.<wbr/> The thumbnail image will always have a smaller Field
-Of View (FOV) than the primary image when aspect ratios differ.<wbr/></p>
-<p>When an <a href="#controls_android.jpeg.orientation">android.<wbr/>jpeg.<wbr/>orientation</a> of non-zero degree is requested,<wbr/>
-the camera device will handle thumbnail rotation in one of the following ways:</p>
-<ul>
-<li>Set the <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>
-  and keep jpeg and thumbnail image data unrotated.<wbr/></li>
-<li>Rotate the jpeg and thumbnail image data and not set
-  <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>.<wbr/> In this
-  case,<wbr/> LIMITED or FULL hardware level devices will report rotated thumnail size in
-  capture result,<wbr/> so the width and height will be interchanged if 90 or 270 degree
-  orientation is requested.<wbr/> LEGACY device will always report unrotated thumbnail
-  size.<wbr/></li>
-</ul>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL must not squeeze or stretch the downscaled primary image to generate thumbnail.<wbr/>
-The cropping must be done on the primary jpeg image rather than the sensor active array.<wbr/>
-The stream cropping rule specified by "S5.<wbr/> Cropping" in camera3.<wbr/>h doesn't apply to the
-thumbnail image cropping.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.jpeg.availableThumbnailSizes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>jpeg.<wbr/>available<wbr/>Thumbnail<wbr/>Sizes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2 x n
-                </span>
-              <span class="entry_type_visibility"> [public as size]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of JPEG thumbnail sizes for <a href="#controls_android.jpeg.thumbnailSize">android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Size</a> supported by this
-camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This list will include at least one non-zero resolution,<wbr/> plus <code>(0,<wbr/>0)</code> for indicating no
-thumbnail should be generated.<wbr/></p>
-<p>Below condiditions will be satisfied for this size list:</p>
-<ul>
-<li>The sizes will be sorted by increasing pixel area (width x height).<wbr/>
-If several resolutions have the same area,<wbr/> they will be sorted by increasing width.<wbr/></li>
-<li>The aspect ratio of the largest thumbnail size will be same as the
-aspect ratio of largest JPEG output size in <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a>.<wbr/>
-The largest size is defined as the size that has the largest pixel area
-in a given size list.<wbr/></li>
-<li>Each output JPEG size in <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> will have at least
-one corresponding size that has the same aspect ratio in availableThumbnailSizes,<wbr/>
-and vice versa.<wbr/></li>
-<li>All non-<code>(0,<wbr/> 0)</code> sizes will have non-zero widths and heights.<wbr/></li>
-</ul>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.jpeg.maxSize">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>jpeg.<wbr/>max<wbr/>Size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Maximum size in bytes for the compressed
-JPEG buffer</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Must be large enough to fit any JPEG produced by
-the camera</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is used for sizing the gralloc buffers for
-JPEG</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.jpeg.gpsLocation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>jpeg.<wbr/>gps<wbr/>Location
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [java_public as location]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A location object to use when generating image GPS metadata.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Setting a location object in a request will include the GPS coordinates of the location
-into any JPEG images captured based on the request.<wbr/> These coordinates can then be
-viewed by anyone who receives the JPEG image.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.jpeg.gpsCoordinates">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>jpeg.<wbr/>gps<wbr/>Coordinates
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">double</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">latitude,<wbr/> longitude,<wbr/> altitude.<wbr/> First two in degrees,<wbr/> the third in meters</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>GPS coordinates to include in output JPEG
-EXIF.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>(-180 - 180],<wbr/> [-90,<wbr/>90],<wbr/> [-inf,<wbr/> inf]</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.jpeg.gpsProcessingMethod">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>jpeg.<wbr/>gps<wbr/>Processing<wbr/>Method
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [ndk_public as string]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>32 characters describing GPS algorithm to
-include in EXIF.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              UTF-8 null-terminated string
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.jpeg.gpsTimestamp">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>jpeg.<wbr/>gps<wbr/>Timestamp
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Time GPS fix was made to include in
-EXIF.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              UTC in seconds since January 1,<wbr/> 1970
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.jpeg.orientation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>jpeg.<wbr/>orientation
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The orientation for a JPEG image.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Degrees in multiples of 90
-            </td>
-
-            <td class="entry_range">
-              <p>0,<wbr/> 90,<wbr/> 180,<wbr/> 270</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The clockwise rotation angle in degrees,<wbr/> relative to the orientation
-to the camera,<wbr/> that the JPEG picture needs to be rotated by,<wbr/> to be viewed
-upright.<wbr/></p>
-<p>Camera devices may either encode this value into the JPEG EXIF header,<wbr/> or
-rotate the image data to match this orientation.<wbr/> When the image data is rotated,<wbr/>
-the thumbnail data will also be rotated.<wbr/></p>
-<p>Note that this orientation is relative to the orientation of the camera sensor,<wbr/> given
-by <a href="#static_android.sensor.orientation">android.<wbr/>sensor.<wbr/>orientation</a>.<wbr/></p>
-<p>To translate from the device orientation given by the Android sensor APIs,<wbr/> the following
-sample code may be used:</p>
-<pre><code>private int getJpegOrientation(CameraCharacteristics c,<wbr/> int deviceOrientation) {
-    if (deviceOrientation == android.<wbr/>view.<wbr/>Orientation<wbr/>Event<wbr/>Listener.<wbr/>ORIENTATION_<wbr/>UNKNOWN) return 0;
-    int sensorOrientation = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>SENSOR_<wbr/>ORIENTATION);
-
-    //<wbr/> Round device orientation to a multiple of 90
-    deviceOrientation = (deviceOrientation + 45) /<wbr/> 90 * 90;
-
-    //<wbr/> Reverse device orientation for front-facing cameras
-    boolean facingFront = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING) == Camera<wbr/>Characteristics.<wbr/>LENS_<wbr/>FACING_<wbr/>FRONT;
-    if (facingFront) deviceOrientation = -deviceOrientation;
-
-    //<wbr/> Calculate desired JPEG orientation relative to camera orientation to make
-    //<wbr/> the image upright relative to the device orientation
-    int jpegOrientation = (sensorOrientation + deviceOrientation + 360) % 360;
-
-    return jpegOrientation;
-}
-</code></pre>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.jpeg.quality">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>jpeg.<wbr/>quality
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Compression quality of the final JPEG
-image.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>1-100; larger is higher quality</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>85-95 is typical usage range.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.jpeg.size">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>jpeg.<wbr/>size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The size of the compressed JPEG image,<wbr/> in
-bytes</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If no JPEG output is produced for the request,<wbr/>
-this must be 0.<wbr/></p>
-<p>Otherwise,<wbr/> this describes the real size of the compressed
-JPEG image placed in the output stream.<wbr/>  More specifically,<wbr/>
-if <a href="#static_android.jpeg.maxSize">android.<wbr/>jpeg.<wbr/>max<wbr/>Size</a> = 1000000,<wbr/> and a specific capture
-has <a href="#dynamic_android.jpeg.size">android.<wbr/>jpeg.<wbr/>size</a> = 500000,<wbr/> then the output buffer from
-the JPEG stream will be 1000000 bytes,<wbr/> of which the first
-500000 make up the real data.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.jpeg.thumbnailQuality">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Quality
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Compression quality of JPEG
-thumbnail.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>1-100; larger is higher quality</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.jpeg.thumbnailSize">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>jpeg.<wbr/>thumbnail<wbr/>Size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as size]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Resolution of embedded JPEG thumbnail.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.jpeg.availableThumbnailSizes">android.<wbr/>jpeg.<wbr/>available<wbr/>Thumbnail<wbr/>Sizes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to (0,<wbr/> 0) value,<wbr/> the JPEG EXIF will not contain thumbnail,<wbr/>
-but the captured JPEG will still be a valid image.<wbr/></p>
-<p>For best results,<wbr/> when issuing a request for a JPEG image,<wbr/> the thumbnail size selected
-should have the same aspect ratio as the main JPEG output.<wbr/></p>
-<p>If the thumbnail image aspect ratio differs from the JPEG primary image aspect
-ratio,<wbr/> the camera device creates the thumbnail by cropping it from the primary image.<wbr/>
-For example,<wbr/> if the primary image has 4:3 aspect ratio,<wbr/> the thumbnail image has
-16:9 aspect ratio,<wbr/> the primary image will be cropped vertically (letterbox) to
-generate the thumbnail image.<wbr/> The thumbnail image will always have a smaller Field
-Of View (FOV) than the primary image when aspect ratios differ.<wbr/></p>
-<p>When an <a href="#controls_android.jpeg.orientation">android.<wbr/>jpeg.<wbr/>orientation</a> of non-zero degree is requested,<wbr/>
-the camera device will handle thumbnail rotation in one of the following ways:</p>
-<ul>
-<li>Set the <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>
-  and keep jpeg and thumbnail image data unrotated.<wbr/></li>
-<li>Rotate the jpeg and thumbnail image data and not set
-  <a href="https://developer.android.com/reference/android/media/ExifInterface.html#TAG_ORIENTATION">EXIF orientation flag</a>.<wbr/> In this
-  case,<wbr/> LIMITED or FULL hardware level devices will report rotated thumnail size in
-  capture result,<wbr/> so the width and height will be interchanged if 90 or 270 degree
-  orientation is requested.<wbr/> LEGACY device will always report unrotated thumbnail
-  size.<wbr/></li>
-</ul>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL must not squeeze or stretch the downscaled primary image to generate thumbnail.<wbr/>
-The cropping must be done on the primary jpeg image rather than the sensor active array.<wbr/>
-The stream cropping rule specified by "S5.<wbr/> Cropping" in camera3.<wbr/>h doesn't apply to the
-thumbnail image cropping.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_lens" class="section">lens</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.lens.aperture">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>aperture
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired lens aperture size,<wbr/> as a ratio of lens focal length to the
-effective aperture diameter.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              The f-number (f/<wbr/>N)
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.lens.info.availableApertures">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Setting this value is only supported on the camera devices that have a variable
-aperture lens.<wbr/></p>
-<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/>
-this can be set along with <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
-<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>
-to achieve manual exposure control.<wbr/></p>
-<p>The requested aperture value may take several frames to reach the
-requested value; the camera device will report the current (intermediate)
-aperture size in capture result metadata while the aperture is changing.<wbr/>
-While the aperture is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p>
-<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of
-the ON modes,<wbr/> this will be overridden by the camera device
-auto-exposure algorithm,<wbr/> the overridden values are then provided
-back to the user in the corresponding result.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.lens.filterDensity">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>filter<wbr/>Density
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired setting for the lens neutral density filter(s).<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Exposure Value (EV)
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.lens.info.availableFilterDensities">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control will not be supported on most camera devices.<wbr/></p>
-<p>Lens filters are typically used to lower the amount of light the
-sensor is exposed to (measured in steps of EV).<wbr/> As used here,<wbr/> an EV
-step is the standard logarithmic representation,<wbr/> which are
-non-negative,<wbr/> and inversely proportional to the amount of light
-hitting the sensor.<wbr/>  For example,<wbr/> setting this to 0 would result
-in no reduction of the incoming light,<wbr/> and setting this to 2 would
-mean that the filter is set to reduce incoming light by two stops
-(allowing 1/<wbr/>4 of the prior amount of light to the sensor).<wbr/></p>
-<p>It may take several frames before the lens filter density changes
-to the requested value.<wbr/> While the filter density is still changing,<wbr/>
-<a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.lens.focalLength">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>focal<wbr/>Length
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired lens focal length; used for optical zoom.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Millimeters
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.lens.info.availableFocalLengths">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This setting controls the physical focal length of the camera
-device's lens.<wbr/> Changing the focal length changes the field of
-view of the camera device,<wbr/> and is usually used for optical zoom.<wbr/></p>
-<p>Like <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>,<wbr/> this
-setting won't be applied instantaneously,<wbr/> and it may take several
-frames before the lens can change to the requested focal length.<wbr/>
-While the focal length is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will
-be set to MOVING.<wbr/></p>
-<p>Optical zoom will not be supported on most devices.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.lens.focusDistance">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>focus<wbr/>Distance
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Desired distance to plane of sharpest focus,<wbr/>
-measured from frontmost surface of the lens.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control can be used for setting manual focus,<wbr/> on devices that support
-the MANUAL_<wbr/>SENSOR capability and have a variable-focus lens (see
-<a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>).<wbr/></p>
-<p>A value of <code>0.<wbr/>0f</code> means infinity focus.<wbr/> The value set will be clamped to
-<code>[0.<wbr/>0f,<wbr/> <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>]</code>.<wbr/></p>
-<p>Like <a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> this setting won't be applied
-instantaneously,<wbr/> and it may take several frames before the lens
-can move to the requested focus distance.<wbr/> While the lens is still moving,<wbr/>
-<a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p>
-<p>LEGACY devices support at most setting this to <code>0.<wbr/>0f</code>
-for infinity focus.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.lens.opticalStabilizationMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Optical stabilization is unavailable.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optical stabilization is enabled.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Sets whether the camera device uses optical image stabilization (OIS)
-when capturing images.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>OIS is used to compensate for motion blur due to small
-movements of the camera during capture.<wbr/> Unlike digital image
-stabilization (<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> OIS
-makes use of mechanical elements to stabilize the camera
-sensor,<wbr/> and thus allows for longer exposure times before
-camera shake becomes apparent.<wbr/></p>
-<p>Switching between different optical stabilization modes may take several
-frames to initialize,<wbr/> the camera device will report the current mode in
-capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/> the
-optical stabilization modes in the first several capture results may still
-be "OFF",<wbr/> and it will become "ON" when the initialization is done.<wbr/></p>
-<p>If a camera device supports both OIS and digital image stabilization
-(<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may produce undesirable
-interaction,<wbr/> so it is recommended not to enable both at the same time.<wbr/></p>
-<p>Not all devices will support OIS; see
-<a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a> for
-available controls.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-                
-            
-
-                
-          <tr class="entry" id="static_android.lens.info.availableApertures">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of aperture size values for <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a> that are
-supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              The aperture f-number
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If the camera device doesn't support a variable lens aperture,<wbr/>
-this list will contain only one value,<wbr/> which is the fixed aperture size.<wbr/></p>
-<p>If the camera device supports a variable aperture,<wbr/> the aperture values
-in this list will be sorted in ascending order.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.info.availableFilterDensities">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of neutral density filter values for
-<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> that are supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Exposure value (EV)
-            </td>
-
-            <td class="entry_range">
-              <p>Values are &gt;= 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If a neutral density filter is not supported by this camera device,<wbr/>
-this list will contain only 0.<wbr/> Otherwise,<wbr/> this list will include every
-filter density supported by the camera device,<wbr/> in ascending order.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.info.availableFocalLengths">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">The list of available focal lengths</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of focal lengths for <a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a> that are supported by this camera
-device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Millimeters
-            </td>
-
-            <td class="entry_range">
-              <p>Values are &gt; 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If optical zoom is not supported,<wbr/> this list will only contain
-a single value corresponding to the fixed focal length of the
-device.<wbr/> Otherwise,<wbr/> this list will include every focal length supported
-by the camera device,<wbr/> in ascending order.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.info.availableOpticalStabilization">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of optical image stabilization (OIS) modes for
-<a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> that are supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If OIS is not supported by a given camera device,<wbr/> this list will
-contain only OFF.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.info.hyperfocalDistance">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>info.<wbr/>hyperfocal<wbr/>Distance
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Hyperfocal distance for this lens.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details
-            </td>
-
-            <td class="entry_range">
-              <p>If lens is fixed focus,<wbr/> &gt;= 0.<wbr/> If lens has focuser unit,<wbr/> the value is
-within <code>(0.<wbr/>0f,<wbr/> <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>]</code></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If the lens is not fixed focus,<wbr/> the camera device will report this
-field when <a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a> is APPROXIMATE or CALIBRATED.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.info.minimumFocusDistance">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Shortest distance from frontmost surface
-of the lens that can be brought into sharp focus.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If the lens is fixed-focus,<wbr/> this will be
-0.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Mandatory for FULL devices; LIMITED devices
-must always set this value to 0 for fixed-focus; and may omit
-the minimum focus distance otherwise.<wbr/></p>
-<p>This field is also mandatory for all devices advertising
-the MANUAL_<wbr/>SENSOR capability.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.info.shadingMapSize">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [ndk_public as size]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">width and height (N,<wbr/> M) of lens shading map provided by the camera device.<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Dimensions of lens shading map.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Both values &gt;= 1</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The map should be on the order of 30-40 rows and columns,<wbr/> and
-must be smaller than 64x64.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.info.focusDistanceCalibration">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">UNCALIBRATED</span>
-                    <span class="entry_type_enum_notes"><p>The lens focus distance is not accurate,<wbr/> and the units used for
-<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> do not correspond to any physical units.<wbr/></p>
-<p>Setting the lens to the same focus distance on separate occasions may
-result in a different real focus distance,<wbr/> depending on factors such
-as the orientation of the device,<wbr/> the age of the focusing mechanism,<wbr/>
-and the device temperature.<wbr/> The focus distance value will still be
-in the range of <code>[0,<wbr/> <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>]</code>,<wbr/> where 0
-represents the farthest focus.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">APPROXIMATE</span>
-                    <span class="entry_type_enum_notes"><p>The lens focus distance is measured in diopters.<wbr/></p>
-<p>However,<wbr/> setting the lens to the same focus distance
-on separate occasions may result in a different real
-focus distance,<wbr/> depending on factors such as the
-orientation of the device,<wbr/> the age of the focusing
-mechanism,<wbr/> and the device temperature.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CALIBRATED</span>
-                    <span class="entry_type_enum_notes"><p>The lens focus distance is measured in diopters,<wbr/> and
-is calibrated.<wbr/></p>
-<p>The lens mechanism is calibrated so that setting the
-same focus distance is repeatable on multiple
-occasions with good accuracy,<wbr/> and the focus distance
-corresponds to the real physical distance to the plane
-of best focus.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The lens focus distance calibration quality.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The lens focus distance calibration quality determines the reliability of
-focus related metadata entries,<wbr/> i.<wbr/>e.<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/>
-<a href="#dynamic_android.lens.focusRange">android.<wbr/>lens.<wbr/>focus<wbr/>Range</a>,<wbr/> <a href="#static_android.lens.info.hyperfocalDistance">android.<wbr/>lens.<wbr/>info.<wbr/>hyperfocal<wbr/>Distance</a>,<wbr/> and
-<a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a>.<wbr/></p>
-<p>APPROXIMATE and CALIBRATED devices report the focus metadata in
-units of diopters (1/<wbr/>meter),<wbr/> so <code>0.<wbr/>0f</code> represents focusing at infinity,<wbr/>
-and increasing positive numbers represent focusing closer and closer
-to the camera device.<wbr/> The focus distance control also uses diopters
-on these devices.<wbr/></p>
-<p>UNCALIBRATED devices do not use units that are directly comparable
-to any real physical measurement,<wbr/> but <code>0.<wbr/>0f</code> still represents farthest
-focus,<wbr/> and <a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> represents the
-nearest focus the device can achieve.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For devices advertise APPROXIMATE quality or higher,<wbr/> diopters 0 (infinity
-focus) must work.<wbr/> When autofocus is disabled (<a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a> == OFF)
-and the lens focus distance is set to 0 diopters
-(<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> == 0),<wbr/> the lens will move to focus at infinity
-and is stably focused at infinity even if the device tilts.<wbr/> It may take the
-lens some time to move; during the move the lens state should be MOVING and
-the output diopter value should be changing toward 0.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-        
-
-                
-          <tr class="entry" id="static_android.lens.facing">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>lens.<wbr/>facing
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">FRONT</span>
-                    <span class="entry_type_enum_notes"><p>The camera device faces the same direction as the device's screen.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">BACK</span>
-                    <span class="entry_type_enum_notes"><p>The camera device faces the opposite direction as the device's screen.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">EXTERNAL</span>
-                    <span class="entry_type_enum_notes"><p>The camera device is an external camera,<wbr/> and has no fixed facing relative to the
-device's screen.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Direction the camera faces relative to
-device screen.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.poseRotation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>pose<wbr/>Rotation
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The orientation of the camera relative to the sensor
-coordinate system.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              
-            Quaternion coefficients
-          
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The four coefficients that describe the quaternion
-rotation from the Android sensor coordinate system to a
-camera-aligned coordinate system where the X-axis is
-aligned with the long side of the image sensor,<wbr/> the Y-axis
-is aligned with the short side of the image sensor,<wbr/> and
-the Z-axis is aligned with the optical axis of the sensor.<wbr/></p>
-<p>To convert from the quaternion coefficients <code>(x,<wbr/>y,<wbr/>z,<wbr/>w)</code>
-to the axis of rotation <code>(a_<wbr/>x,<wbr/> a_<wbr/>y,<wbr/> a_<wbr/>z)</code> and rotation
-amount <code>theta</code>,<wbr/> the following formulas can be used:</p>
-<pre><code> theta = 2 * acos(w)
-a_<wbr/>x = x /<wbr/> sin(theta/<wbr/>2)
-a_<wbr/>y = y /<wbr/> sin(theta/<wbr/>2)
-a_<wbr/>z = z /<wbr/> sin(theta/<wbr/>2)
-</code></pre>
-<p>To create a 3x3 rotation matrix that applies the rotation
-defined by this quaternion,<wbr/> the following matrix can be
-used:</p>
-<pre><code>R = [ 1 - 2y^2 - 2z^2,<wbr/>       2xy - 2zw,<wbr/>       2xz + 2yw,<wbr/>
-           2xy + 2zw,<wbr/> 1 - 2x^2 - 2z^2,<wbr/>       2yz - 2xw,<wbr/>
-           2xz - 2yw,<wbr/>       2yz + 2xw,<wbr/> 1 - 2x^2 - 2y^2 ]
-</code></pre>
-<p>This matrix can then be used to apply the rotation to a
- column vector point with</p>
-<p><code>p' = Rp</code></p>
-<p>where <code>p</code> is in the device sensor coordinate system,<wbr/> and
- <code>p'</code> is in the camera-oriented coordinate system.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.poseTranslation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>pose<wbr/>Translation
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Position of the camera optical center.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Meters
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The position of the camera device's lens optical center,<wbr/>
-as a three-dimensional vector <code>(x,<wbr/>y,<wbr/>z)</code>,<wbr/> relative to the
-optical center of the largest camera device facing in the
-same direction as this camera,<wbr/> in the <a href="https://developer.android.com/reference/android/hardware/SensorEvent.html">Android sensor coordinate
-axes</a>.<wbr/> Note that only the axis definitions are shared with
-the sensor coordinate system,<wbr/> but not the origin.<wbr/></p>
-<p>If this device is the largest or only camera device with a
-given facing,<wbr/> then this position will be <code>(0,<wbr/> 0,<wbr/> 0)</code>; a
-camera device with a lens optical center located 3 cm from
-the main sensor along the +X axis (to the right from the
-user's perspective) will report <code>(0.<wbr/>03,<wbr/> 0,<wbr/> 0)</code>.<wbr/></p>
-<p>To transform a pixel coordinates between two cameras
-facing the same direction,<wbr/> first the source camera
-<a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a> must be corrected for.<wbr/>  Then
-the source camera <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> needs
-to be applied,<wbr/> followed by the <a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a>
-of the source camera,<wbr/> the translation of the source camera
-relative to the destination camera,<wbr/> the
-<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> of the destination camera,<wbr/> and
-finally the inverse of <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a>
-of the destination camera.<wbr/> This obtains a
-radial-distortion-free coordinate in the destination
-camera pixel coordinates.<wbr/></p>
-<p>To compare this against a real image from the destination
-camera,<wbr/> the destination camera image then needs to be
-corrected for radial distortion before comparison or
-sampling.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.intrinsicCalibration">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  5
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The parameters for this camera device's intrinsic
-calibration.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              
-            Pixels in the
-            android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size
-            coordinate system.<wbr/>
-          
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The five calibration parameters that describe the
-transform from camera-centric 3D coordinates to sensor
-pixel coordinates:</p>
-<pre><code>[f_<wbr/>x,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>x,<wbr/> c_<wbr/>y,<wbr/> s]
-</code></pre>
-<p>Where <code>f_<wbr/>x</code> and <code>f_<wbr/>y</code> are the horizontal and vertical
-focal lengths,<wbr/> <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code> is the position of the optical
-axis,<wbr/> and <code>s</code> is a skew parameter for the sensor plane not
-being aligned with the lens plane.<wbr/></p>
-<p>These are typically used within a transformation matrix K:</p>
-<pre><code>K = [ f_<wbr/>x,<wbr/>   s,<wbr/> c_<wbr/>x,<wbr/>
-       0,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>y,<wbr/>
-       0    0,<wbr/>   1 ]
-</code></pre>
-<p>which can then be combined with the camera pose rotation
-<code>R</code> and translation <code>t</code> (<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> and
-<a href="#static_android.lens.poseTranslation">android.<wbr/>lens.<wbr/>pose<wbr/>Translation</a>,<wbr/> respective) to calculate the
-complete transform from world coordinates to pixel
-coordinates:</p>
-<pre><code>P = [ K 0   * [ R t
-     0 1 ]     0 1 ]
-</code></pre>
-<p>and with <code>p_<wbr/>w</code> being a point in the world coordinate system
-and <code>p_<wbr/>s</code> being a point in the camera active pixel array
-coordinate system,<wbr/> and with the mapping including the
-homogeneous division by z:</p>
-<pre><code> p_<wbr/>h = (x_<wbr/>h,<wbr/> y_<wbr/>h,<wbr/> z_<wbr/>h) = P p_<wbr/>w
-p_<wbr/>s = p_<wbr/>h /<wbr/> z_<wbr/>h
-</code></pre>
-<p>so <code>[x_<wbr/>s,<wbr/> y_<wbr/>s]</code> is the pixel coordinates of the world
-point,<wbr/> <code>z_<wbr/>s = 1</code>,<wbr/> and <code>w_<wbr/>s</code> is a measurement of disparity
-(depth) in pixel coordinates.<wbr/></p>
-<p>Note that the coordinate system for this transform is the
-<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> system,<wbr/>
-where <code>(0,<wbr/>0)</code> is the top-left of the
-preCorrectionActiveArraySize rectangle.<wbr/> Once the pose and
-intrinsic calibration transforms have been applied to a
-world point,<wbr/> then the <a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a>
-transform needs to be applied,<wbr/> and the result adjusted to
-be in the <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> coordinate
-system (where <code>(0,<wbr/> 0)</code> is the top-left of the
-activeArraySize rectangle),<wbr/> to determine the final pixel
-coordinate of the world point for processed (non-RAW)
-output buffers.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.lens.radialDistortion">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>radial<wbr/>Distortion
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  6
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The correction coefficients to correct for this camera device's
-radial and tangential lens distortion.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              
-            Unitless coefficients.<wbr/>
-          
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Four radial distortion coefficients <code>[kappa_<wbr/>0,<wbr/> kappa_<wbr/>1,<wbr/> kappa_<wbr/>2,<wbr/>
-kappa_<wbr/>3]</code> and two tangential distortion coefficients
-<code>[kappa_<wbr/>4,<wbr/> kappa_<wbr/>5]</code> that can be used to correct the
-lens's geometric distortion with the mapping equations:</p>
-<pre><code> x_<wbr/>c = x_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) +
-       kappa_<wbr/>4 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>5 * ( r^2 + 2 * x_<wbr/>i^2 )
- y_<wbr/>c = y_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) +
-       kappa_<wbr/>5 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>4 * ( r^2 + 2 * y_<wbr/>i^2 )
-</code></pre>
-<p>Here,<wbr/> <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> are the coordinates to sample in the
-input image that correspond to the pixel values in the
-corrected image at the coordinate <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code>:</p>
-<pre><code> correctedImage(x_<wbr/>i,<wbr/> y_<wbr/>i) = sample_<wbr/>at(x_<wbr/>c,<wbr/> y_<wbr/>c,<wbr/> inputImage)
-</code></pre>
-<p>The pixel coordinates are defined in a normalized
-coordinate system related to the
-<a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> calibration fields.<wbr/>
-Both <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code> and <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> have <code>(0,<wbr/>0)</code> at the
-lens optical center <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code>.<wbr/> The maximum magnitudes
-of both x and y coordinates are normalized to be 1 at the
-edge further from the optical center,<wbr/> so the range
-for both dimensions is <code>-1 &lt;= x &lt;= 1</code>.<wbr/></p>
-<p>Finally,<wbr/> <code>r</code> represents the radial distance from the
-optical center,<wbr/> <code>r^2 = x_<wbr/>i^2 + y_<wbr/>i^2</code>,<wbr/> and its magnitude
-is therefore no larger than <code>|<wbr/>r|<wbr/> &lt;= sqrt(2)</code>.<wbr/></p>
-<p>The distortion model used is the Brown-Conrady model.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.lens.aperture">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>aperture
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired lens aperture size,<wbr/> as a ratio of lens focal length to the
-effective aperture diameter.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              The f-number (f/<wbr/>N)
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.lens.info.availableApertures">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Setting this value is only supported on the camera devices that have a variable
-aperture lens.<wbr/></p>
-<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is OFF,<wbr/>
-this can be set along with <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>,<wbr/>
-<a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>,<wbr/> and <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a>
-to achieve manual exposure control.<wbr/></p>
-<p>The requested aperture value may take several frames to reach the
-requested value; the camera device will report the current (intermediate)
-aperture size in capture result metadata while the aperture is changing.<wbr/>
-While the aperture is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p>
-<p>When this is supported and <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> is one of
-the ON modes,<wbr/> this will be overridden by the camera device
-auto-exposure algorithm,<wbr/> the overridden values are then provided
-back to the user in the corresponding result.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.lens.filterDensity">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>filter<wbr/>Density
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired setting for the lens neutral density filter(s).<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Exposure Value (EV)
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.lens.info.availableFilterDensities">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control will not be supported on most camera devices.<wbr/></p>
-<p>Lens filters are typically used to lower the amount of light the
-sensor is exposed to (measured in steps of EV).<wbr/> As used here,<wbr/> an EV
-step is the standard logarithmic representation,<wbr/> which are
-non-negative,<wbr/> and inversely proportional to the amount of light
-hitting the sensor.<wbr/>  For example,<wbr/> setting this to 0 would result
-in no reduction of the incoming light,<wbr/> and setting this to 2 would
-mean that the filter is set to reduce incoming light by two stops
-(allowing 1/<wbr/>4 of the prior amount of light to the sensor).<wbr/></p>
-<p>It may take several frames before the lens filter density changes
-to the requested value.<wbr/> While the filter density is still changing,<wbr/>
-<a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will be set to MOVING.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.lens.focalLength">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>focal<wbr/>Length
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired lens focal length; used for optical zoom.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Millimeters
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.lens.info.availableFocalLengths">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This setting controls the physical focal length of the camera
-device's lens.<wbr/> Changing the focal length changes the field of
-view of the camera device,<wbr/> and is usually used for optical zoom.<wbr/></p>
-<p>Like <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>,<wbr/> this
-setting won't be applied instantaneously,<wbr/> and it may take several
-frames before the lens can change to the requested focal length.<wbr/>
-While the focal length is still changing,<wbr/> <a href="#dynamic_android.lens.state">android.<wbr/>lens.<wbr/>state</a> will
-be set to MOVING.<wbr/></p>
-<p>Optical zoom will not be supported on most devices.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.lens.focusDistance">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>focus<wbr/>Distance
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Desired distance to plane of sharpest focus,<wbr/>
-measured from frontmost surface of the lens.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              See android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Should be zero for fixed-focus cameras</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.lens.focusRange">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>focus<wbr/>Range
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as pairFloatFloat]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-                <div class="entry_type_notes">Range of scene distances that are in focus</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The range of scene distances that are in
-sharp focus (depth of field).<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              A pair of focus distances in diopters: (near,<wbr/>
-          far); see android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration for details.<wbr/>
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;=0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If variable focus not supported,<wbr/> can still report
-fixed depth of field range</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.lens.opticalStabilizationMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Optical stabilization is unavailable.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Optical stabilization is enabled.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Sets whether the camera device uses optical image stabilization (OIS)
-when capturing images.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>OIS is used to compensate for motion blur due to small
-movements of the camera during capture.<wbr/> Unlike digital image
-stabilization (<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> OIS
-makes use of mechanical elements to stabilize the camera
-sensor,<wbr/> and thus allows for longer exposure times before
-camera shake becomes apparent.<wbr/></p>
-<p>Switching between different optical stabilization modes may take several
-frames to initialize,<wbr/> the camera device will report the current mode in
-capture result metadata.<wbr/> For example,<wbr/> When "ON" mode is requested,<wbr/> the
-optical stabilization modes in the first several capture results may still
-be "OFF",<wbr/> and it will become "ON" when the initialization is done.<wbr/></p>
-<p>If a camera device supports both OIS and digital image stabilization
-(<a href="#controls_android.control.videoStabilizationMode">android.<wbr/>control.<wbr/>video<wbr/>Stabilization<wbr/>Mode</a>),<wbr/> turning both modes on may produce undesirable
-interaction,<wbr/> so it is recommended not to enable both at the same time.<wbr/></p>
-<p>Not all devices will support OIS; see
-<a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a> for
-available controls.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.lens.state">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>state
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">STATIONARY</span>
-                    <span class="entry_type_enum_notes"><p>The lens parameters (<a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/>
-<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>) are not changing.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MOVING</span>
-                    <span class="entry_type_enum_notes"><p>One or several of the lens parameters
-(<a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/>
-<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> or <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>) is
-currently changing.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Current lens status.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For lens parameters <a href="#controls_android.lens.focalLength">android.<wbr/>lens.<wbr/>focal<wbr/>Length</a>,<wbr/> <a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a>,<wbr/>
-<a href="#controls_android.lens.filterDensity">android.<wbr/>lens.<wbr/>filter<wbr/>Density</a> and <a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a>,<wbr/> when changes are requested,<wbr/>
-they may take several frames to reach the requested values.<wbr/> This state indicates
-the current status of the lens parameters.<wbr/></p>
-<p>When the state is STATIONARY,<wbr/> the lens parameters are not changing.<wbr/> This could be
-either because the parameters are all fixed,<wbr/> or because the lens has had enough
-time to reach the most recently-requested values.<wbr/>
-If all these lens parameters are not changable for a camera device,<wbr/> as listed below:</p>
-<ul>
-<li>Fixed focus (<code><a href="#static_android.lens.info.minimumFocusDistance">android.<wbr/>lens.<wbr/>info.<wbr/>minimum<wbr/>Focus<wbr/>Distance</a> == 0</code>),<wbr/> which means
-<a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a> parameter will always be 0.<wbr/></li>
-<li>Fixed focal length (<a href="#static_android.lens.info.availableFocalLengths">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Focal<wbr/>Lengths</a> contains single value),<wbr/>
-which means the optical zoom is not supported.<wbr/></li>
-<li>No ND filter (<a href="#static_android.lens.info.availableFilterDensities">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Filter<wbr/>Densities</a> contains only 0).<wbr/></li>
-<li>Fixed aperture (<a href="#static_android.lens.info.availableApertures">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Apertures</a> contains single value).<wbr/></li>
-</ul>
-<p>Then this state will always be STATIONARY.<wbr/></p>
-<p>When the state is MOVING,<wbr/> it indicates that at least one of the lens parameters
-is changing.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.lens.poseRotation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>pose<wbr/>Rotation
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The orientation of the camera relative to the sensor
-coordinate system.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              
-            Quaternion coefficients
-          
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The four coefficients that describe the quaternion
-rotation from the Android sensor coordinate system to a
-camera-aligned coordinate system where the X-axis is
-aligned with the long side of the image sensor,<wbr/> the Y-axis
-is aligned with the short side of the image sensor,<wbr/> and
-the Z-axis is aligned with the optical axis of the sensor.<wbr/></p>
-<p>To convert from the quaternion coefficients <code>(x,<wbr/>y,<wbr/>z,<wbr/>w)</code>
-to the axis of rotation <code>(a_<wbr/>x,<wbr/> a_<wbr/>y,<wbr/> a_<wbr/>z)</code> and rotation
-amount <code>theta</code>,<wbr/> the following formulas can be used:</p>
-<pre><code> theta = 2 * acos(w)
-a_<wbr/>x = x /<wbr/> sin(theta/<wbr/>2)
-a_<wbr/>y = y /<wbr/> sin(theta/<wbr/>2)
-a_<wbr/>z = z /<wbr/> sin(theta/<wbr/>2)
-</code></pre>
-<p>To create a 3x3 rotation matrix that applies the rotation
-defined by this quaternion,<wbr/> the following matrix can be
-used:</p>
-<pre><code>R = [ 1 - 2y^2 - 2z^2,<wbr/>       2xy - 2zw,<wbr/>       2xz + 2yw,<wbr/>
-           2xy + 2zw,<wbr/> 1 - 2x^2 - 2z^2,<wbr/>       2yz - 2xw,<wbr/>
-           2xz - 2yw,<wbr/>       2yz + 2xw,<wbr/> 1 - 2x^2 - 2y^2 ]
-</code></pre>
-<p>This matrix can then be used to apply the rotation to a
- column vector point with</p>
-<p><code>p' = Rp</code></p>
-<p>where <code>p</code> is in the device sensor coordinate system,<wbr/> and
- <code>p'</code> is in the camera-oriented coordinate system.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.lens.poseTranslation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>pose<wbr/>Translation
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Position of the camera optical center.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Meters
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The position of the camera device's lens optical center,<wbr/>
-as a three-dimensional vector <code>(x,<wbr/>y,<wbr/>z)</code>,<wbr/> relative to the
-optical center of the largest camera device facing in the
-same direction as this camera,<wbr/> in the <a href="https://developer.android.com/reference/android/hardware/SensorEvent.html">Android sensor coordinate
-axes</a>.<wbr/> Note that only the axis definitions are shared with
-the sensor coordinate system,<wbr/> but not the origin.<wbr/></p>
-<p>If this device is the largest or only camera device with a
-given facing,<wbr/> then this position will be <code>(0,<wbr/> 0,<wbr/> 0)</code>; a
-camera device with a lens optical center located 3 cm from
-the main sensor along the +X axis (to the right from the
-user's perspective) will report <code>(0.<wbr/>03,<wbr/> 0,<wbr/> 0)</code>.<wbr/></p>
-<p>To transform a pixel coordinates between two cameras
-facing the same direction,<wbr/> first the source camera
-<a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a> must be corrected for.<wbr/>  Then
-the source camera <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> needs
-to be applied,<wbr/> followed by the <a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a>
-of the source camera,<wbr/> the translation of the source camera
-relative to the destination camera,<wbr/> the
-<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> of the destination camera,<wbr/> and
-finally the inverse of <a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a>
-of the destination camera.<wbr/> This obtains a
-radial-distortion-free coordinate in the destination
-camera pixel coordinates.<wbr/></p>
-<p>To compare this against a real image from the destination
-camera,<wbr/> the destination camera image then needs to be
-corrected for radial distortion before comparison or
-sampling.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.lens.intrinsicCalibration">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  5
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The parameters for this camera device's intrinsic
-calibration.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              
-            Pixels in the
-            android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size
-            coordinate system.<wbr/>
-          
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The five calibration parameters that describe the
-transform from camera-centric 3D coordinates to sensor
-pixel coordinates:</p>
-<pre><code>[f_<wbr/>x,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>x,<wbr/> c_<wbr/>y,<wbr/> s]
-</code></pre>
-<p>Where <code>f_<wbr/>x</code> and <code>f_<wbr/>y</code> are the horizontal and vertical
-focal lengths,<wbr/> <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code> is the position of the optical
-axis,<wbr/> and <code>s</code> is a skew parameter for the sensor plane not
-being aligned with the lens plane.<wbr/></p>
-<p>These are typically used within a transformation matrix K:</p>
-<pre><code>K = [ f_<wbr/>x,<wbr/>   s,<wbr/> c_<wbr/>x,<wbr/>
-       0,<wbr/> f_<wbr/>y,<wbr/> c_<wbr/>y,<wbr/>
-       0    0,<wbr/>   1 ]
-</code></pre>
-<p>which can then be combined with the camera pose rotation
-<code>R</code> and translation <code>t</code> (<a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a> and
-<a href="#static_android.lens.poseTranslation">android.<wbr/>lens.<wbr/>pose<wbr/>Translation</a>,<wbr/> respective) to calculate the
-complete transform from world coordinates to pixel
-coordinates:</p>
-<pre><code>P = [ K 0   * [ R t
-     0 1 ]     0 1 ]
-</code></pre>
-<p>and with <code>p_<wbr/>w</code> being a point in the world coordinate system
-and <code>p_<wbr/>s</code> being a point in the camera active pixel array
-coordinate system,<wbr/> and with the mapping including the
-homogeneous division by z:</p>
-<pre><code> p_<wbr/>h = (x_<wbr/>h,<wbr/> y_<wbr/>h,<wbr/> z_<wbr/>h) = P p_<wbr/>w
-p_<wbr/>s = p_<wbr/>h /<wbr/> z_<wbr/>h
-</code></pre>
-<p>so <code>[x_<wbr/>s,<wbr/> y_<wbr/>s]</code> is the pixel coordinates of the world
-point,<wbr/> <code>z_<wbr/>s = 1</code>,<wbr/> and <code>w_<wbr/>s</code> is a measurement of disparity
-(depth) in pixel coordinates.<wbr/></p>
-<p>Note that the coordinate system for this transform is the
-<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> system,<wbr/>
-where <code>(0,<wbr/>0)</code> is the top-left of the
-preCorrectionActiveArraySize rectangle.<wbr/> Once the pose and
-intrinsic calibration transforms have been applied to a
-world point,<wbr/> then the <a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a>
-transform needs to be applied,<wbr/> and the result adjusted to
-be in the <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> coordinate
-system (where <code>(0,<wbr/> 0)</code> is the top-left of the
-activeArraySize rectangle),<wbr/> to determine the final pixel
-coordinate of the world point for processed (non-RAW)
-output buffers.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.lens.radialDistortion">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>lens.<wbr/>radial<wbr/>Distortion
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  6
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The correction coefficients to correct for this camera device's
-radial and tangential lens distortion.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              
-            Unitless coefficients.<wbr/>
-          
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Four radial distortion coefficients <code>[kappa_<wbr/>0,<wbr/> kappa_<wbr/>1,<wbr/> kappa_<wbr/>2,<wbr/>
-kappa_<wbr/>3]</code> and two tangential distortion coefficients
-<code>[kappa_<wbr/>4,<wbr/> kappa_<wbr/>5]</code> that can be used to correct the
-lens's geometric distortion with the mapping equations:</p>
-<pre><code> x_<wbr/>c = x_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) +
-       kappa_<wbr/>4 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>5 * ( r^2 + 2 * x_<wbr/>i^2 )
- y_<wbr/>c = y_<wbr/>i * ( kappa_<wbr/>0 + kappa_<wbr/>1 * r^2 + kappa_<wbr/>2 * r^4 + kappa_<wbr/>3 * r^6 ) +
-       kappa_<wbr/>5 * (2 * x_<wbr/>i * y_<wbr/>i) + kappa_<wbr/>4 * ( r^2 + 2 * y_<wbr/>i^2 )
-</code></pre>
-<p>Here,<wbr/> <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> are the coordinates to sample in the
-input image that correspond to the pixel values in the
-corrected image at the coordinate <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code>:</p>
-<pre><code> correctedImage(x_<wbr/>i,<wbr/> y_<wbr/>i) = sample_<wbr/>at(x_<wbr/>c,<wbr/> y_<wbr/>c,<wbr/> inputImage)
-</code></pre>
-<p>The pixel coordinates are defined in a normalized
-coordinate system related to the
-<a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a> calibration fields.<wbr/>
-Both <code>[x_<wbr/>i,<wbr/> y_<wbr/>i]</code> and <code>[x_<wbr/>c,<wbr/> y_<wbr/>c]</code> have <code>(0,<wbr/>0)</code> at the
-lens optical center <code>[c_<wbr/>x,<wbr/> c_<wbr/>y]</code>.<wbr/> The maximum magnitudes
-of both x and y coordinates are normalized to be 1 at the
-edge further from the optical center,<wbr/> so the range
-for both dimensions is <code>-1 &lt;= x &lt;= 1</code>.<wbr/></p>
-<p>Finally,<wbr/> <code>r</code> represents the radial distance from the
-optical center,<wbr/> <code>r^2 = x_<wbr/>i^2 + y_<wbr/>i^2</code>,<wbr/> and its magnitude
-is therefore no larger than <code>|<wbr/>r|<wbr/> &lt;= sqrt(2)</code>.<wbr/></p>
-<p>The distortion model used is the Brown-Conrady model.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_noiseReduction" class="section">noiseReduction</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.noiseReduction.mode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>noise<wbr/>Reduction.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No noise reduction is applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Noise reduction is applied without reducing frame rate relative to sensor
-output.<wbr/> It may be the same as OFF if noise reduction will reduce frame rate
-relative to sensor.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>High-quality noise reduction is applied,<wbr/> at the cost of possibly reduced frame
-rate relative to sensor output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MINIMAL</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>MINIMAL noise reduction is applied without reducing frame rate relative to
-sensor output.<wbr/> </p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Noise reduction is applied at different levels for different output streams,<wbr/>
-based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have noise
-reduction applied,<wbr/> while higher-resolution streams have MINIMAL (if supported) or no
-noise reduction applied (if MINIMAL is not supported.<wbr/>) The degree of noise reduction
-for low-resolution streams is tuned so that frame rate is not impacted,<wbr/> and the quality
-is equal to or better than FAST (since it is only applied to lower-resolution outputs,<wbr/>
-quality may improve from FAST).<wbr/></p>
-<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
-with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures
-high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is
-produced via reprocessing when a user takes a picture.<wbr/>  For such a use case,<wbr/> the
-high-resolution buffers must not have noise reduction applied to maximize efficiency of
-preview and to avoid over-applying noise filtering when reprocessing,<wbr/> while
-low-resolution buffers (used for recording or preview,<wbr/> generally) need noise reduction
-applied for reasonable preview quality.<wbr/></p>
-<p>This mode is guaranteed to be supported by devices that support either the
-YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities
-(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will
-be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Mode of operation for the noise reduction algorithm.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The noise reduction algorithm attempts to improve image quality by removing
-excessive noise added by the capture process,<wbr/> especially in dark conditions.<wbr/></p>
-<p>OFF means no noise reduction will be applied by the camera device,<wbr/> for both raw and
-YUV domain.<wbr/></p>
-<p>MINIMAL means that only sensor raw domain basic noise reduction is enabled ,<wbr/>to remove
-demosaicing or other processing artifacts.<wbr/> For YUV_<wbr/>REPROCESSING,<wbr/> MINIMAL is same as OFF.<wbr/>
-This mode is optional,<wbr/> may not be support by all devices.<wbr/> The application should check
-<a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> before using it.<wbr/></p>
-<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined noise filtering
-will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device
-will use the highest-quality noise filtering algorithms,<wbr/>
-even if it slows down capture rate.<wbr/> FAST means the camera device will not
-slow down capture rate when applying noise filtering.<wbr/> FAST may be the same as MINIMAL if
-MINIMAL is listed,<wbr/> or the same as OFF if any noise filtering will slow down capture rate.<wbr/>
-Every output stream will have a similar amount of enhancement applied.<wbr/></p>
-<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular
-buffer of high-resolution images during preview and reprocess image(s) from that buffer
-into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies
-noise reduction to low-resolution streams (below maximum recording resolution) to maximize
-preview quality,<wbr/> but does not apply noise reduction to high-resolution streams,<wbr/> since
-those will be reprocessed later if necessary.<wbr/></p>
-<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera device
-will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV domain noise reduction,<wbr/> respectively.<wbr/> The camera device
-may adjust the noise reduction parameters for best image quality based on the
-<a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> if it is set.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to
-adjust the internal noise reduction parameters appropriately to get the best quality
-images.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.noiseReduction.strength">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>noise<wbr/>Reduction.<wbr/>strength
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Control the amount of noise reduction
-applied to the images</p>
-            </td>
-
-            <td class="entry_units">
-              1-10; 10 is max noise reduction
-            </td>
-
-            <td class="entry_range">
-              <p>1 - 10</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.noiseReduction.availableNoiseReductionModes">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of noise reduction modes for <a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a> that are supported
-by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Full-capability camera devices will always support OFF and FAST.<wbr/></p>
-<p>Camera devices that support YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING will support
-ZERO_<wbr/>SHUTTER_<wbr/>LAG.<wbr/></p>
-<p>Legacy-capability camera devices will only support FAST mode.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if noise reduction control is available
-on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
-That is,<wbr/> if the highest quality implementation on the camera device does not slow down
-capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.noiseReduction.mode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>noise<wbr/>Reduction.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No noise reduction is applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Noise reduction is applied without reducing frame rate relative to sensor
-output.<wbr/> It may be the same as OFF if noise reduction will reduce frame rate
-relative to sensor.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>High-quality noise reduction is applied,<wbr/> at the cost of possibly reduced frame
-rate relative to sensor output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MINIMAL</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>MINIMAL noise reduction is applied without reducing frame rate relative to
-sensor output.<wbr/> </p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ZERO_SHUTTER_LAG</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Noise reduction is applied at different levels for different output streams,<wbr/>
-based on resolution.<wbr/> Streams at maximum recording resolution (see <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a>) or below have noise
-reduction applied,<wbr/> while higher-resolution streams have MINIMAL (if supported) or no
-noise reduction applied (if MINIMAL is not supported.<wbr/>) The degree of noise reduction
-for low-resolution streams is tuned so that frame rate is not impacted,<wbr/> and the quality
-is equal to or better than FAST (since it is only applied to lower-resolution outputs,<wbr/>
-quality may improve from FAST).<wbr/></p>
-<p>This mode is intended to be used by applications operating in a zero-shutter-lag mode
-with YUV or PRIVATE reprocessing,<wbr/> where the application continuously captures
-high-resolution intermediate buffers into a circular buffer,<wbr/> from which a final image is
-produced via reprocessing when a user takes a picture.<wbr/>  For such a use case,<wbr/> the
-high-resolution buffers must not have noise reduction applied to maximize efficiency of
-preview and to avoid over-applying noise filtering when reprocessing,<wbr/> while
-low-resolution buffers (used for recording or preview,<wbr/> generally) need noise reduction
-applied for reasonable preview quality.<wbr/></p>
-<p>This mode is guaranteed to be supported by devices that support either the
-YUV_<wbr/>REPROCESSING or PRIVATE_<wbr/>REPROCESSING capabilities
-(<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> lists either of those capabilities) and it will
-be the default mode for CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Mode of operation for the noise reduction algorithm.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The noise reduction algorithm attempts to improve image quality by removing
-excessive noise added by the capture process,<wbr/> especially in dark conditions.<wbr/></p>
-<p>OFF means no noise reduction will be applied by the camera device,<wbr/> for both raw and
-YUV domain.<wbr/></p>
-<p>MINIMAL means that only sensor raw domain basic noise reduction is enabled ,<wbr/>to remove
-demosaicing or other processing artifacts.<wbr/> For YUV_<wbr/>REPROCESSING,<wbr/> MINIMAL is same as OFF.<wbr/>
-This mode is optional,<wbr/> may not be support by all devices.<wbr/> The application should check
-<a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> before using it.<wbr/></p>
-<p>FAST/<wbr/>HIGH_<wbr/>QUALITY both mean camera device determined noise filtering
-will be applied.<wbr/> HIGH_<wbr/>QUALITY mode indicates that the camera device
-will use the highest-quality noise filtering algorithms,<wbr/>
-even if it slows down capture rate.<wbr/> FAST means the camera device will not
-slow down capture rate when applying noise filtering.<wbr/> FAST may be the same as MINIMAL if
-MINIMAL is listed,<wbr/> or the same as OFF if any noise filtering will slow down capture rate.<wbr/>
-Every output stream will have a similar amount of enhancement applied.<wbr/></p>
-<p>ZERO_<wbr/>SHUTTER_<wbr/>LAG is meant to be used by applications that maintain a continuous circular
-buffer of high-resolution images during preview and reprocess image(s) from that buffer
-into a final capture when triggered by the user.<wbr/> In this mode,<wbr/> the camera device applies
-noise reduction to low-resolution streams (below maximum recording resolution) to maximize
-preview quality,<wbr/> but does not apply noise reduction to high-resolution streams,<wbr/> since
-those will be reprocessed later if necessary.<wbr/></p>
-<p>For YUV_<wbr/>REPROCESSING,<wbr/> these FAST/<wbr/>HIGH_<wbr/>QUALITY modes both mean that the camera device
-will apply FAST/<wbr/>HIGH_<wbr/>QUALITY YUV domain noise reduction,<wbr/> respectively.<wbr/> The camera device
-may adjust the noise reduction parameters for best image quality based on the
-<a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> if it is set.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For YUV_<wbr/>REPROCESSING The HAL can use <a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a> to
-adjust the internal noise reduction parameters appropriately to get the best quality
-images.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_quirks" class="section">quirks</td></tr>
-
-
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.quirks.meteringCropRegion">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>quirks.<wbr/>metering<wbr/>Crop<wbr/>Region
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>If set to 1,<wbr/> the camera service does not
-scale 'normalized' coordinates with respect to the crop
-region.<wbr/> This applies to metering input (a{e,<wbr/>f,<wbr/>wb}Region
-and output (face rectangles).<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Normalized coordinates refer to those in the
-(-1000,<wbr/>1000) range mentioned in the
-android.<wbr/>hardware.<wbr/>Camera API.<wbr/></p>
-<p>HAL implementations should instead always use and emit
-sensor array-relative coordinates for all region data.<wbr/> Does
-not need to be listed in static metadata.<wbr/> Support will be
-removed in future versions of camera service.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.quirks.triggerAfWithAuto">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>quirks.<wbr/>trigger<wbr/>Af<wbr/>With<wbr/>Auto
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>If set to 1,<wbr/> then the camera service always
-switches to FOCUS_<wbr/>MODE_<wbr/>AUTO before issuing a AF
-trigger.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL implementations should implement AF trigger
-modes for AUTO,<wbr/> MACRO,<wbr/> CONTINUOUS_<wbr/>FOCUS,<wbr/> and
-CONTINUOUS_<wbr/>PICTURE modes instead of using this flag.<wbr/> Does
-not need to be listed in static metadata.<wbr/> Support will be
-removed in future versions of camera service</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.quirks.useZslFormat">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>quirks.<wbr/>use<wbr/>Zsl<wbr/>Format
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>If set to 1,<wbr/> the camera service uses
-CAMERA2_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>ZSL instead of
-HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>IMPLEMENTATION_<wbr/>DEFINED for the zero
-shutter lag stream</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL implementations should use gralloc usage flags
-to determine that a stream will be used for
-zero-shutter-lag,<wbr/> instead of relying on an explicit
-format setting.<wbr/> Does not need to be listed in static
-metadata.<wbr/> Support will be removed in future versions of
-camera service.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.quirks.usePartialResult">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="5">
-              android.<wbr/>quirks.<wbr/>use<wbr/>Partial<wbr/>Result
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [hidden]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>If set to 1,<wbr/> the HAL will always split result
-metadata for a single capture into multiple buffers,<wbr/>
-returned using multiple process_<wbr/>capture_<wbr/>result calls.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Does not need to be listed in static
-metadata.<wbr/> Support for partial results will be reworked in
-future versions of camera service.<wbr/> This quirk will stop
-working at that point; DO NOT USE without careful
-consideration of future support.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Refer to <code>camera3_<wbr/>capture_<wbr/>result::partial_<wbr/>result</code>
-for information on how to implement partial results.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.quirks.partialResult">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="5">
-              android.<wbr/>quirks.<wbr/>partial<wbr/>Result
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [hidden as boolean]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">FINAL</span>
-                    <span class="entry_type_enum_notes"><p>The last or only metadata result buffer
-for this capture.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PARTIAL</span>
-                    <span class="entry_type_enum_notes"><p>A partial buffer of result metadata for this
-capture.<wbr/> More result buffers for this capture will be sent
-by the camera device,<wbr/> the last of which will be marked
-FINAL.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether a result given to the framework is the
-final one for the capture,<wbr/> or only a partial that contains a
-subset of the full set of dynamic metadata
-values.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-              <p>Optional.<wbr/> Default value is FINAL.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The entries in the result metadata buffers for a
-single capture may not overlap,<wbr/> except for this entry.<wbr/> The
-FINAL buffers must retain FIFO ordering relative to the
-requests that generate them,<wbr/> so the FINAL buffer for frame 3 must
-always be sent to the framework after the FINAL buffer for frame 2,<wbr/> and
-before the FINAL buffer for frame 4.<wbr/> PARTIAL buffers may be returned
-in any order relative to other frames,<wbr/> but all PARTIAL buffers for a given
-capture must arrive before the FINAL buffer for that capture.<wbr/> This entry may
-only be used by the camera device if quirks.<wbr/>usePartialResult is set to 1.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Refer to <code>camera3_<wbr/>capture_<wbr/>result::partial_<wbr/>result</code>
-for information on how to implement partial results.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_request" class="section">request</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.request.frameCount">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="1">
-              android.<wbr/>request.<wbr/>frame<wbr/>Count
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A frame counter set by the framework.<wbr/> Must
-be maintained unchanged in output frame.<wbr/> This value monotonically
-increases with every new result (that is,<wbr/> each new result has a unique
-frameCount value).<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              incrementing integer
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-              <p>Any int.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.request.id">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>request.<wbr/>id
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [hidden]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>An application-specified ID for the current
-request.<wbr/> Must be maintained unchanged in output
-frame</p>
-            </td>
-
-            <td class="entry_units">
-              arbitrary integer assigned by application
-            </td>
-
-            <td class="entry_range">
-              <p>Any int</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.request.inputStreams">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>request.<wbr/>input<wbr/>Streams
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List which camera reprocess stream is used
-for the source of reprocessing data.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              List of camera reprocess stream IDs
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-              <p>Typically,<wbr/> only one entry allowed,<wbr/> must be a valid reprocess stream ID.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_HAL2">HAL2</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Only meaningful when <a href="#controls_android.request.type">android.<wbr/>request.<wbr/>type</a> ==
-REPROCESS.<wbr/> Ignored otherwise</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.request.metadataMode">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>request.<wbr/>metadata<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">NONE</span>
-                    <span class="entry_type_enum_notes"><p>No metadata should be produced on output,<wbr/> except
-for application-bound buffer data.<wbr/> If no
-application-bound streams exist,<wbr/> no frame should be
-placed in the output frame queue.<wbr/> If such streams
-exist,<wbr/> a frame should be placed on the output queue
-with null metadata but with the necessary output buffer
-information.<wbr/> Timestamp information should still be
-included with any output stream buffers</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FULL</span>
-                    <span class="entry_type_enum_notes"><p>All metadata should be produced.<wbr/> Statistics will
-only be produced if they are separately
-enabled</p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>How much metadata to produce on
-output</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.request.outputStreams">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>request.<wbr/>output<wbr/>Streams
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Lists which camera output streams image data
-from this capture must be sent to</p>
-            </td>
-
-            <td class="entry_units">
-              List of camera stream IDs
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-              <p>List must only include streams that have been
-created</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_HAL2">HAL2</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If no output streams are listed,<wbr/> then the image
-data should simply be discarded.<wbr/> The image data must
-still be captured for metadata and statistics production,<wbr/>
-and the lens and flash must operate as requested.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.request.type">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="1">
-              android.<wbr/>request.<wbr/>type
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">CAPTURE</span>
-                    <span class="entry_type_enum_notes"><p>Capture a new image from the imaging hardware,<wbr/>
-and process it according to the
-settings</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">REPROCESS</span>
-                    <span class="entry_type_enum_notes"><p>Process previously captured data; the
-<a href="#controls_android.request.inputStreams">android.<wbr/>request.<wbr/>input<wbr/>Streams</a> parameter determines the
-source reprocessing stream.<wbr/> TODO: Mark dynamic metadata
-needed for reprocessing with [RP]</p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The type of the request; either CAPTURE or
-REPROCESS.<wbr/> For HAL3,<wbr/> this tag is redundant.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_HAL2">HAL2</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.request.maxNumOutputStreams">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Streams
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum numbers of different types of output streams
-that can be configured and used simultaneously by a camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>For processed (and stalling) format streams,<wbr/> &gt;= 1.<wbr/></p>
-<p>For Raw format (either stalling or non-stalling) streams,<wbr/> &gt;= 0.<wbr/></p>
-<p>For processed (but not stalling) format streams,<wbr/> &gt;= 3
-for FULL mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>);
-&gt;= 2 for LIMITED mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>).<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is a 3 element tuple that contains the max number of output simultaneous
-streams for raw sensor,<wbr/> processed (but not stalling),<wbr/> and processed (and stalling)
-formats respectively.<wbr/> For example,<wbr/> assuming that JPEG is typically a processed and
-stalling stream,<wbr/> if max raw sensor format output stream number is 1,<wbr/> max YUV streams
-number is 3,<wbr/> and max JPEG stream number is 2,<wbr/> then this tuple should be <code>(1,<wbr/> 3,<wbr/> 2)</code>.<wbr/></p>
-<p>This lists the upper bound of the number of output streams supported by
-the camera device.<wbr/> Using more streams simultaneously may require more hardware and
-CPU resources that will consume more power.<wbr/> The image format for an output stream can
-be any supported format provided by <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a>.<wbr/>
-The formats defined in <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> can be catergorized
-into the 3 stream types as below:</p>
-<ul>
-<li>Processed (but stalling): any non-RAW format with a stallDurations &gt; 0.<wbr/>
-  Typically <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">JPEG format</a>.<wbr/></li>
-<li>Raw formats: <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_SENSOR">RAW_<wbr/>SENSOR</a>,<wbr/> <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">RAW10</a>,<wbr/> or <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW12">RAW12</a>.<wbr/></li>
-<li>Processed (but not-stalling): any non-RAW format without a stall duration.<wbr/>
-  Typically <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">YUV_<wbr/>420_<wbr/>888</a>,<wbr/>
-  <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a>,<wbr/> or
-  <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a>.<wbr/></li>
-</ul>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.maxNumOutputRaw">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Raw
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [java_public]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum numbers of different types of output streams
-that can be configured and used simultaneously by a camera device
-for any <code>RAW</code> formats.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This value contains the max number of output simultaneous
-streams from the raw sensor.<wbr/></p>
-<p>This lists the upper bound of the number of output streams supported by
-the camera device.<wbr/> Using more streams simultaneously may require more hardware and
-CPU resources that will consume more power.<wbr/> The image format for this kind of an output stream can
-be any <code>RAW</code> and supported format provided by <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/></p>
-<p>In particular,<wbr/> a <code>RAW</code> format is typically one of:</p>
-<ul>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_SENSOR">RAW_<wbr/>SENSOR</a></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">RAW10</a></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW12">RAW12</a></li>
-</ul>
-<p>LEGACY mode devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> <code>==</code> LEGACY)
-never support raw streams.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.maxNumOutputProc">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Proc
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [java_public]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum numbers of different types of output streams
-that can be configured and used simultaneously by a camera device
-for any processed (but not-stalling) formats.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 3
-for FULL mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>);
-&gt;= 2 for LIMITED mode devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>).<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This value contains the max number of output simultaneous
-streams for any processed (but not-stalling) formats.<wbr/></p>
-<p>This lists the upper bound of the number of output streams supported by
-the camera device.<wbr/> Using more streams simultaneously may require more hardware and
-CPU resources that will consume more power.<wbr/> The image format for this kind of an output stream can
-be any non-<code>RAW</code> and supported format provided by <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/></p>
-<p>Processed (but not-stalling) is defined as any non-RAW format without a stall duration.<wbr/>
-Typically:</p>
-<ul>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">YUV_<wbr/>420_<wbr/>888</a></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#NV21">NV21</a></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12">YV12</a></li>
-<li>Implementation-defined formats,<wbr/> i.<wbr/>e.<wbr/> <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#isOutputSupportedFor(Class)">StreamConfigurationMap#isOutputSupportedFor(Class)</a></li>
-</ul>
-<p>For full guarantees,<wbr/> query <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> with a
-processed format -- it will return 0 for a non-stalling stream.<wbr/></p>
-<p>LEGACY devices will support at least 2 processing/<wbr/>non-stalling streams.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.maxNumOutputProcStalling">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Proc<wbr/>Stalling
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [java_public]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum numbers of different types of output streams
-that can be configured and used simultaneously by a camera device
-for any processed (and stalling) formats.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 1</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This value contains the max number of output simultaneous
-streams for any processed (but not-stalling) formats.<wbr/></p>
-<p>This lists the upper bound of the number of output streams supported by
-the camera device.<wbr/> Using more streams simultaneously may require more hardware and
-CPU resources that will consume more power.<wbr/> The image format for this kind of an output stream can
-be any non-<code>RAW</code> and supported format provided by <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/></p>
-<p>A processed and stalling format is defined as any non-RAW format with a stallDurations
-&gt; 0.<wbr/>  Typically only the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">JPEG format</a> is a
-stalling format.<wbr/></p>
-<p>For full guarantees,<wbr/> query <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> with a
-processed format -- it will return a non-0 value for a stalling stream.<wbr/></p>
-<p>LEGACY devices will support up to 1 processing/<wbr/>stalling stream.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.maxNumReprocessStreams">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Reprocess<wbr/>Streams
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  1
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>How many reprocessing streams of any type
-can be allocated at the same time.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-              <p>&gt;= 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_HAL2">HAL2</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Only used by HAL2.<wbr/>x.<wbr/></p>
-<p>When set to 0,<wbr/> it means no reprocess stream is supported.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.maxNumInputStreams">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum numbers of any type of input streams
-that can be configured and used simultaneously by a camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>0 or 1.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to 0,<wbr/> it means no input stream is supported.<wbr/></p>
-<p>The image format for a input stream can be any supported format returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a>.<wbr/> When using an
-input stream,<wbr/> there must be at least one output stream configured to to receive the
-reprocessed images.<wbr/></p>
-<p>When an input stream and some output streams are used in a reprocessing request,<wbr/>
-only the input buffer will be used to produce these output stream buffers,<wbr/> and a
-new sensor image will not be captured.<wbr/></p>
-<p>For example,<wbr/> for Zero Shutter Lag (ZSL) still capture use case,<wbr/> the input
-stream image format will be PRIVATE,<wbr/> the associated output stream image format
-should be JPEG.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For the reprocessing flow and controls,<wbr/> see
-hardware/<wbr/>libhardware/<wbr/>include/<wbr/>hardware/<wbr/>camera3.<wbr/>h Section 10 for more details.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.pipelineMaxDepth">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Specifies the number of maximum pipeline stages a frame
-has to go through from when it's exposed to when it's available
-to the framework.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>A typical minimum value for this is 2 (one stage to expose,<wbr/>
-one stage to readout) from the sensor.<wbr/> The ISP then usually adds
-its own stages to do custom HW processing.<wbr/> Further stages may be
-added by SW processing.<wbr/></p>
-<p>Depending on what settings are used (e.<wbr/>g.<wbr/> YUV,<wbr/> JPEG) and what
-processing is enabled (e.<wbr/>g.<wbr/> face detection),<wbr/> the actual pipeline
-depth (specified by <a href="#dynamic_android.request.pipelineDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Depth</a>) may be less than
-the max pipeline depth.<wbr/></p>
-<p>A pipeline depth of X stages is equivalent to a pipeline latency of
-X frame intervals.<wbr/></p>
-<p>This value will normally be 8 or less,<wbr/> however,<wbr/> for high speed capture session,<wbr/>
-the max pipeline depth will be up to 8 x size of high speed capture request list.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This value should be 4 or less,<wbr/> expect for the high speed recording session,<wbr/> where the
-max batch sizes may be larger than 1.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.partialResultCount">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>request.<wbr/>partial<wbr/>Result<wbr/>Count
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Defines how many sub-components
-a result will be composed of.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 1</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>In order to combat the pipeline latency,<wbr/> partial results
-may be delivered to the application layer from the camera device as
-soon as they are available.<wbr/></p>
-<p>Optional; defaults to 1.<wbr/> A value of 1 means that partial
-results are not supported,<wbr/> and only the final TotalCaptureResult will
-be produced by the camera device.<wbr/></p>
-<p>A typical use case for this might be: after requesting an
-auto-focus (AF) lock the new AF state might be available 50%
-of the way through the pipeline.<wbr/>  The camera device could
-then immediately dispatch this state via a partial result to
-the application,<wbr/> and the rest of the metadata via later
-partial results.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.availableCapabilities">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>request.<wbr/>available<wbr/>Capabilities
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">BACKWARD_COMPATIBLE</span>
-                    <span class="entry_type_enum_notes"><p>The minimal set of capabilities that every camera
-device (regardless of <a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a>)
-supports.<wbr/></p>
-<p>This capability is listed by all normal devices,<wbr/> and
-indicates that the camera device has a feature set
-that's comparable to the baseline requirements for the
-older android.<wbr/>hardware.<wbr/>Camera API.<wbr/></p>
-<p>Devices with the DEPTH_<wbr/>OUTPUT capability might not list this
-capability,<wbr/> indicating that they support only depth measurement,<wbr/>
-not standard color output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MANUAL_SENSOR</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>The camera device can be manually controlled (3A algorithms such
-as auto-exposure,<wbr/> and auto-focus can be bypassed).<wbr/>
-The camera device supports basic manual control of the sensor image
-acquisition related stages.<wbr/> This means the following controls are
-guaranteed to be supported:</p>
-<ul>
-<li>Manual frame duration control<ul>
-<li><a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a></li>
-<li><a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a></li>
-</ul>
-</li>
-<li>Manual exposure control<ul>
-<li><a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a></li>
-<li><a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></li>
-</ul>
-</li>
-<li>Manual sensitivity control<ul>
-<li><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></li>
-<li><a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a></li>
-</ul>
-</li>
-<li>Manual lens control (if the lens is adjustable)<ul>
-<li>android.<wbr/>lens.<wbr/>*</li>
-</ul>
-</li>
-<li>Manual flash control (if a flash unit is present)<ul>
-<li>android.<wbr/>flash.<wbr/>*</li>
-</ul>
-</li>
-<li>Manual black level locking<ul>
-<li><a href="#controls_android.blackLevel.lock">android.<wbr/>black<wbr/>Level.<wbr/>lock</a></li>
-</ul>
-</li>
-<li>Auto exposure lock<ul>
-<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li>
-</ul>
-</li>
-</ul>
-<p>If any of the above 3A algorithms are enabled,<wbr/> then the camera
-device will accurately report the values applied by 3A in the
-result.<wbr/></p>
-<p>A given camera device may also support additional manual sensor controls,<wbr/>
-but this capability only covers the above list of controls.<wbr/></p>
-<p>If this is supported,<wbr/> <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> will
-additionally return a min frame duration that is greater than
-zero for each supported size-format combination.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">MANUAL_POST_PROCESSING</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>The camera device post-processing stages can be manually controlled.<wbr/>
-The camera device supports basic manual control of the image post-processing
-stages.<wbr/> This means the following controls are guaranteed to be supported:</p>
-<ul>
-<li>
-<p>Manual tonemap control</p>
-<ul>
-<li><a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a></li>
-<li><a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a></li>
-<li><a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></li>
-<li><a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a></li>
-<li><a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a></li>
-</ul>
-</li>
-<li>
-<p>Manual white balance control</p>
-<ul>
-<li><a href="#controls_android.colorCorrection.transform">android.<wbr/>color<wbr/>Correction.<wbr/>transform</a></li>
-<li><a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a></li>
-</ul>
-</li>
-<li>Manual lens shading map control<ul>
-<li><a href="#controls_android.shading.mode">android.<wbr/>shading.<wbr/>mode</a></li>
-<li><a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a></li>
-<li><a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a></li>
-<li><a href="#static_android.lens.info.shadingMapSize">android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size</a></li>
-</ul>
-</li>
-<li>Manual aberration correction control (if aberration correction is supported)<ul>
-<li><a href="#controls_android.colorCorrection.aberrationMode">android.<wbr/>color<wbr/>Correction.<wbr/>aberration<wbr/>Mode</a></li>
-<li><a href="#static_android.colorCorrection.availableAberrationModes">android.<wbr/>color<wbr/>Correction.<wbr/>available<wbr/>Aberration<wbr/>Modes</a></li>
-</ul>
-</li>
-<li>Auto white balance lock<ul>
-<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li>
-</ul>
-</li>
-</ul>
-<p>If auto white balance is enabled,<wbr/> then the camera device
-will accurately report the values applied by AWB in the result.<wbr/></p>
-<p>A given camera device may also support additional post-processing
-controls,<wbr/> but this capability only covers the above list of controls.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">RAW</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>The camera device supports outputting RAW buffers and
-metadata for interpreting them.<wbr/></p>
-<p>Devices supporting the RAW capability allow both for
-saving DNG files,<wbr/> and for direct application processing of
-raw sensor images.<wbr/></p>
-<ul>
-<li>RAW_<wbr/>SENSOR is supported as an output format.<wbr/></li>
-<li>The maximum available resolution for RAW_<wbr/>SENSOR streams
-  will match either the value in
-  <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a> or
-  <a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>.<wbr/></li>
-<li>All DNG-related optional metadata entries are provided
-  by the camera device.<wbr/></li>
-</ul></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PRIVATE_REPROCESSING</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>The camera device supports the Zero Shutter Lag reprocessing use case.<wbr/></p>
-<ul>
-<li>One input stream is supported,<wbr/> that is,<wbr/> <code><a href="#static_android.request.maxNumInputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams</a> == 1</code>.<wbr/></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> is supported as an output/<wbr/>input format,<wbr/>
-  that is,<wbr/> <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> is included in the lists of
-  formats returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a> and <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputFormats">StreamConfigurationMap#getOutputFormats</a>.<wbr/></li>
-<li><a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getValidOutputFormatsForInput">StreamConfigurationMap#getValidOutputFormatsForInput</a>
-  returns non empty int[] for each supported input format returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a>.<wbr/></li>
-<li>Each size returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputSizes">getInputSizes(ImageFormat.<wbr/>PRIVATE)</a> is also included in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">getOutputSizes(ImageFormat.<wbr/>PRIVATE)</a></li>
-<li>Using <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> does not cause a frame rate drop
-  relative to the sensor's maximum capture rate (at that resolution).<wbr/></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> will be reprocessable into both
-  <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> and
-  <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a> formats.<wbr/></li>
-<li>The maximum available resolution for PRIVATE streams
-  (both input/<wbr/>output) will match the maximum available
-  resolution of JPEG streams.<wbr/></li>
-<li>Static metadata <a href="#static_android.reprocess.maxCaptureStall">android.<wbr/>reprocess.<wbr/>max<wbr/>Capture<wbr/>Stall</a>.<wbr/></li>
-<li>Only below controls are effective for reprocessing requests and
-  will be present in capture results,<wbr/> other controls in reprocess
-  requests will be ignored by the camera device.<wbr/><ul>
-<li>android.<wbr/>jpeg.<wbr/>*</li>
-<li><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a></li>
-<li><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a></li>
-</ul>
-</li>
-<li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> and
-  <a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a> will both list ZERO_<wbr/>SHUTTER_<wbr/>LAG as a supported mode.<wbr/></li>
-</ul></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">READ_SENSOR_SETTINGS</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>The camera device supports accurately reporting the sensor settings for many of
-the sensor controls while the built-in 3A algorithm is running.<wbr/>  This allows
-reporting of sensor settings even when these settings cannot be manually changed.<wbr/></p>
-<p>The values reported for the following controls are guaranteed to be available
-in the CaptureResult,<wbr/> including when 3A is enabled:</p>
-<ul>
-<li>Exposure control<ul>
-<li><a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a></li>
-</ul>
-</li>
-<li>Sensitivity control<ul>
-<li><a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a></li>
-</ul>
-</li>
-<li>Lens controls (if the lens is adjustable)<ul>
-<li><a href="#controls_android.lens.focusDistance">android.<wbr/>lens.<wbr/>focus<wbr/>Distance</a></li>
-<li><a href="#controls_android.lens.aperture">android.<wbr/>lens.<wbr/>aperture</a></li>
-</ul>
-</li>
-</ul>
-<p>This capability is a subset of the MANUAL_<wbr/>SENSOR control capability,<wbr/> and will
-always be included if the MANUAL_<wbr/>SENSOR capability is available.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">BURST_CAPTURE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>The camera device supports capturing high-resolution images at &gt;= 20 frames per
-second,<wbr/> in at least the uncompressed YUV format,<wbr/> when post-processing settings are set
-to FAST.<wbr/> Additionally,<wbr/> maximum-resolution images can be captured at &gt;= 10 frames
-per second.<wbr/>  Here,<wbr/> 'high resolution' means at least 8 megapixels,<wbr/> or the maximum
-resolution of the device,<wbr/> whichever is smaller.<wbr/></p>
-<p>More specifically,<wbr/> this means that a size matching the camera device's active array
-size is listed as a supported size for the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> format in either <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">StreamConfigurationMap#getOutputSizes</a> or <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighResolutionOutputSizes">StreamConfigurationMap#getHighResolutionOutputSizes</a>,<wbr/>
-with a minimum frame duration for that format and size of either &lt;= 1/<wbr/>20 s,<wbr/> or
-&lt;= 1/<wbr/>10 s,<wbr/> respectively; and the <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a> entry
-lists at least one FPS range where the minimum FPS is &gt;= 1 /<wbr/> minimumFrameDuration
-for the maximum-size YUV_<wbr/>420_<wbr/>888 format.<wbr/>  If that maximum size is listed in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighResolutionOutputSizes">StreamConfigurationMap#getHighResolutionOutputSizes</a>,<wbr/>
-then the list of resolutions for YUV_<wbr/>420_<wbr/>888 from <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">StreamConfigurationMap#getOutputSizes</a> contains at
-least one resolution &gt;= 8 megapixels,<wbr/> with a minimum frame duration of &lt;= 1/<wbr/>20
-s.<wbr/></p>
-<p>If the device supports the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">ImageFormat#RAW10</a>,<wbr/> <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW12">ImageFormat#RAW12</a>,<wbr/> then those can also be captured at the same rate
-as the maximum-size YUV_<wbr/>420_<wbr/>888 resolution is.<wbr/></p>
-<p>If the device supports the PRIVATE_<wbr/>REPROCESSING capability,<wbr/> then the same guarantees
-as for the YUV_<wbr/>420_<wbr/>888 format also apply to the <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> format.<wbr/></p>
-<p>In addition,<wbr/> the <a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a> field is guaranted to have a value between 0
-and 4,<wbr/> inclusive.<wbr/> <a href="#static_android.control.aeLockAvailable">android.<wbr/>control.<wbr/>ae<wbr/>Lock<wbr/>Available</a> and <a href="#static_android.control.awbLockAvailable">android.<wbr/>control.<wbr/>awb<wbr/>Lock<wbr/>Available</a>
-are also guaranteed to be <code>true</code> so burst capture with these two locks ON yields
-consistent image output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">YUV_REPROCESSING</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>The camera device supports the YUV_<wbr/>420_<wbr/>888 reprocessing use case,<wbr/> similar as
-PRIVATE_<wbr/>REPROCESSING,<wbr/> This capability requires the camera device to support the
-following:</p>
-<ul>
-<li>One input stream is supported,<wbr/> that is,<wbr/> <code><a href="#static_android.request.maxNumInputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams</a> == 1</code>.<wbr/></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> is supported as an output/<wbr/>input format,<wbr/> that is,<wbr/>
-  YUV_<wbr/>420_<wbr/>888 is included in the lists of formats returned by
-  <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a> and
-  <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputFormats">StreamConfigurationMap#getOutputFormats</a>.<wbr/></li>
-<li><a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getValidOutputFormatsForInput">StreamConfigurationMap#getValidOutputFormatsForInput</a>
-  returns non-empty int[] for each supported input format returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputFormats">StreamConfigurationMap#getInputFormats</a>.<wbr/></li>
-<li>Each size returned by <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getInputSizes">get<wbr/>Input<wbr/>Sizes(YUV_<wbr/>420_<wbr/>888)</a> is also included in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputSizes">get<wbr/>Output<wbr/>Sizes(YUV_<wbr/>420_<wbr/>888)</a></li>
-<li>Using <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> does not cause a frame rate drop
-  relative to the sensor's maximum capture rate (at that resolution).<wbr/></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> will be reprocessable into both
-  <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> and <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a> formats.<wbr/></li>
-<li>The maximum available resolution for <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a> streams (both input/<wbr/>output) will match the
-  maximum available resolution of <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a> streams.<wbr/></li>
-<li>Static metadata <a href="#static_android.reprocess.maxCaptureStall">android.<wbr/>reprocess.<wbr/>max<wbr/>Capture<wbr/>Stall</a>.<wbr/></li>
-<li>Only the below controls are effective for reprocessing requests and will be present
-  in capture results.<wbr/> The reprocess requests are from the original capture results that
-  are associated with the intermediate <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a>
-  output buffers.<wbr/>  All other controls in the reprocess requests will be ignored by the
-  camera device.<wbr/><ul>
-<li>android.<wbr/>jpeg.<wbr/>*</li>
-<li><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a></li>
-<li><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a></li>
-<li><a href="#controls_android.reprocess.effectiveExposureFactor">android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor</a></li>
-</ul>
-</li>
-<li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.<wbr/>noise<wbr/>Reduction.<wbr/>available<wbr/>Noise<wbr/>Reduction<wbr/>Modes</a> and
-  <a href="#static_android.edge.availableEdgeModes">android.<wbr/>edge.<wbr/>available<wbr/>Edge<wbr/>Modes</a> will both list ZERO_<wbr/>SHUTTER_<wbr/>LAG as a supported mode.<wbr/></li>
-</ul></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">DEPTH_OUTPUT</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>The camera device can produce depth measurements from its field of view.<wbr/></p>
-<p>This capability requires the camera device to support the following:</p>
-<ul>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#DEPTH16">ImageFormat#DEPTH16</a> is supported as an output format.<wbr/></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#DEPTH_POINT_CLOUD">Image<wbr/>Format#DEPTH_<wbr/>POINT_<wbr/>CLOUD</a> is optionally supported as an
-  output format.<wbr/></li>
-<li>This camera device,<wbr/> and all camera devices with the same <a href="#static_android.lens.facing">android.<wbr/>lens.<wbr/>facing</a>,<wbr/>
-  will list the following calibration entries in both
-  <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a> and
-  <a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">CaptureResult</a>:<ul>
-<li><a href="#static_android.lens.poseTranslation">android.<wbr/>lens.<wbr/>pose<wbr/>Translation</a></li>
-<li><a href="#static_android.lens.poseRotation">android.<wbr/>lens.<wbr/>pose<wbr/>Rotation</a></li>
-<li><a href="#static_android.lens.intrinsicCalibration">android.<wbr/>lens.<wbr/>intrinsic<wbr/>Calibration</a></li>
-<li><a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a></li>
-</ul>
-</li>
-<li>The <a href="#static_android.depth.depthIsExclusive">android.<wbr/>depth.<wbr/>depth<wbr/>Is<wbr/>Exclusive</a> entry is listed by this device.<wbr/></li>
-<li>A LIMITED camera with only the DEPTH_<wbr/>OUTPUT capability does not have to support
-  normal YUV_<wbr/>420_<wbr/>888,<wbr/> JPEG,<wbr/> and PRIV-format outputs.<wbr/> It only has to support the DEPTH16
-  format.<wbr/></li>
-</ul>
-<p>Generally,<wbr/> depth output operates at a slower frame rate than standard color capture,<wbr/>
-so the DEPTH16 and DEPTH_<wbr/>POINT_<wbr/>CLOUD formats will commonly have a stall duration that
-should be accounted for (see
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>).<wbr/>
-On a device that supports both depth and color-based output,<wbr/> to enable smooth preview,<wbr/>
-using a repeating burst is recommended,<wbr/> where a depth-output target is only included
-once every N frames,<wbr/> where N is the ratio between preview output rate and depth output
-rate,<wbr/> including depth stall time.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CONSTRAINED_HIGH_SPEED_VIDEO</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>The device supports constrained high speed video recording (frame rate &gt;=120fps)
-use case.<wbr/> The camera device will support high speed capture session created by
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>,<wbr/> which
-only accepts high speed request lists created by
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraConstrainedHighSpeedCaptureSession.html#createHighSpeedRequestList">CameraConstrainedHighSpeedCaptureSession#createHighSpeedRequestList</a>.<wbr/></p>
-<p>A camera device can still support high speed video streaming by advertising the high speed
-FPS ranges in <a href="#static_android.control.aeAvailableTargetFpsRanges">android.<wbr/>control.<wbr/>ae<wbr/>Available<wbr/>Target<wbr/>Fps<wbr/>Ranges</a>.<wbr/> For this case,<wbr/> all normal
-capture request per frame control and synchronization requirements will apply to
-the high speed fps ranges,<wbr/> the same as all other fps ranges.<wbr/> This capability describes
-the capability of a specialized operating mode with many limitations (see below),<wbr/> which
-is only targeted at high speed video recording.<wbr/></p>
-<p>The supported high speed video sizes and fps ranges are specified in
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoFpsRanges">StreamConfigurationMap#getHighSpeedVideoFpsRanges</a>.<wbr/>
-To get desired output frame rates,<wbr/> the application is only allowed to select video size
-and FPS range combinations provided by
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoSizes">StreamConfigurationMap#getHighSpeedVideoSizes</a>.<wbr/>
-The fps range can be controlled via <a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a>.<wbr/></p>
-<p>In this capability,<wbr/> the camera device will override aeMode,<wbr/> awbMode,<wbr/> and afMode to
-ON,<wbr/> AUTO,<wbr/> and CONTINUOUS_<wbr/>VIDEO,<wbr/> respectively.<wbr/> All post-processing block mode
-controls will be overridden to be FAST.<wbr/> Therefore,<wbr/> no manual control of capture
-and post-processing parameters is possible.<wbr/> All other controls operate the
-same as when <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> == AUTO.<wbr/> This means that all other
-android.<wbr/>control.<wbr/>* fields continue to work,<wbr/> such as</p>
-<ul>
-<li><a href="#controls_android.control.aeTargetFpsRange">android.<wbr/>control.<wbr/>ae<wbr/>Target<wbr/>Fps<wbr/>Range</a></li>
-<li><a href="#controls_android.control.aeExposureCompensation">android.<wbr/>control.<wbr/>ae<wbr/>Exposure<wbr/>Compensation</a></li>
-<li><a href="#controls_android.control.aeLock">android.<wbr/>control.<wbr/>ae<wbr/>Lock</a></li>
-<li><a href="#controls_android.control.awbLock">android.<wbr/>control.<wbr/>awb<wbr/>Lock</a></li>
-<li><a href="#controls_android.control.effectMode">android.<wbr/>control.<wbr/>effect<wbr/>Mode</a></li>
-<li><a href="#controls_android.control.aeRegions">android.<wbr/>control.<wbr/>ae<wbr/>Regions</a></li>
-<li><a href="#controls_android.control.afRegions">android.<wbr/>control.<wbr/>af<wbr/>Regions</a></li>
-<li><a href="#controls_android.control.awbRegions">android.<wbr/>control.<wbr/>awb<wbr/>Regions</a></li>
-<li><a href="#controls_android.control.afTrigger">android.<wbr/>control.<wbr/>af<wbr/>Trigger</a></li>
-<li><a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a></li>
-</ul>
-<p>Outside of android.<wbr/>control.<wbr/>*,<wbr/> the following controls will work:</p>
-<ul>
-<li><a href="#controls_android.flash.mode">android.<wbr/>flash.<wbr/>mode</a> (TORCH mode only,<wbr/> automatic flash for still capture will not
-work since aeMode is ON)</li>
-<li><a href="#controls_android.lens.opticalStabilizationMode">android.<wbr/>lens.<wbr/>optical<wbr/>Stabilization<wbr/>Mode</a> (if it is supported)</li>
-<li><a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a></li>
-<li><a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> (if it is supported)</li>
-</ul>
-<p>For high speed recording use case,<wbr/> the actual maximum supported frame rate may
-be lower than what camera can output,<wbr/> depending on the destination Surfaces for
-the image data.<wbr/> For example,<wbr/> if the destination surface is from video encoder,<wbr/>
-the application need check if the video encoder is capable of supporting the
-high frame rate for a given video size,<wbr/> or it will end up with lower recording
-frame rate.<wbr/> If the destination surface is from preview window,<wbr/> the actual preview frame
-rate will be bounded by the screen refresh rate.<wbr/></p>
-<p>The camera device will only support up to 2 high speed simultaneous output surfaces
-(preview and recording surfaces)
-in this mode.<wbr/> Above controls will be effective only if all of below conditions are true:</p>
-<ul>
-<li>The application creates a camera capture session with no more than 2 surfaces via
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>.<wbr/> The
-targeted surfaces must be preview surface (either from
-<a href="https://developer.android.com/reference/android/view/SurfaceView.html">SurfaceView</a> or <a href="https://developer.android.com/reference/android/graphics/SurfaceTexture.html">SurfaceTexture</a>) or
-recording surface(either from <a href="https://developer.android.com/reference/android/media/MediaRecorder.html#getSurface">MediaRecorder#getSurface</a> or
-<a href="https://developer.android.com/reference/android/media/MediaCodec.html#createInputSurface">MediaCodec#createInputSurface</a>).<wbr/></li>
-<li>The stream sizes are selected from the sizes reported by
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoSizes">StreamConfigurationMap#getHighSpeedVideoSizes</a>.<wbr/></li>
-<li>The FPS ranges are selected from
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getHighSpeedVideoFpsRanges">StreamConfigurationMap#getHighSpeedVideoFpsRanges</a>.<wbr/></li>
-</ul>
-<p>When above conditions are NOT satistied,<wbr/>
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createConstrainedHighSpeedCaptureSession">CameraDevice#createConstrainedHighSpeedCaptureSession</a>
-will fail.<wbr/></p>
-<p>Switching to a FPS range that has different maximum FPS may trigger some camera device
-reconfigurations,<wbr/> which may introduce extra latency.<wbr/> It is recommended that
-the application avoids unnecessary maximum target FPS changes as much as possible
-during high speed streaming.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of capabilities that this camera device
-advertises as fully supporting.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>A capability is a contract that the camera device makes in order
-to be able to satisfy one or more use cases.<wbr/></p>
-<p>Listing a capability guarantees that the whole set of features
-required to support a common use will all be available.<wbr/></p>
-<p>Using a subset of the functionality provided by an unsupported
-capability may be possible on a specific camera device implementation;
-to do this query each of <a href="#static_android.request.availableRequestKeys">android.<wbr/>request.<wbr/>available<wbr/>Request<wbr/>Keys</a>,<wbr/>
-<a href="#static_android.request.availableResultKeys">android.<wbr/>request.<wbr/>available<wbr/>Result<wbr/>Keys</a>,<wbr/>
-<a href="#static_android.request.availableCharacteristicsKeys">android.<wbr/>request.<wbr/>available<wbr/>Characteristics<wbr/>Keys</a>.<wbr/></p>
-<p>The following capabilities are guaranteed to be available on
-<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> <code>==</code> FULL devices:</p>
-<ul>
-<li>MANUAL_<wbr/>SENSOR</li>
-<li>MANUAL_<wbr/>POST_<wbr/>PROCESSING</li>
-</ul>
-<p>Other capabilities may be available on either FULL or LIMITED
-devices,<wbr/> but the application should query this key to be sure.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Additional constraint details per-capability will be available
-in the Compatibility Test Suite.<wbr/></p>
-<p>Minimum baseline requirements required for the
-BACKWARD_<wbr/>COMPATIBLE capability are not explicitly listed.<wbr/>
-Instead refer to "BC" tags and the camera CTS tests in the
-android.<wbr/>hardware.<wbr/>camera2.<wbr/>cts package.<wbr/></p>
-<p>Listed controls that can be either request or result (e.<wbr/>g.<wbr/>
-<a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a>) must be available both in the
-request and the result in order to be considered to be
-capability-compliant.<wbr/></p>
-<p>For example,<wbr/> if the HAL claims to support MANUAL control,<wbr/>
-then exposure time must be configurable via the request <em>and</em>
-the actual exposure applied must be available via
-the result.<wbr/></p>
-<p>If MANUAL_<wbr/>SENSOR is omitted,<wbr/> the HAL may choose to omit the
-<a href="#static_android.scaler.availableMinFrameDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Min<wbr/>Frame<wbr/>Durations</a> static property entirely.<wbr/></p>
-<p>For PRIVATE_<wbr/>REPROCESSING and YUV_<wbr/>REPROCESSING capabilities,<wbr/> see
-hardware/<wbr/>libhardware/<wbr/>include/<wbr/>hardware/<wbr/>camera3.<wbr/>h Section 10 for more information.<wbr/></p>
-<p>Devices that support the MANUAL_<wbr/>SENSOR capability must support the
-CAMERA3_<wbr/>TEMPLATE_<wbr/>MANUAL template defined in camera3.<wbr/>h.<wbr/></p>
-<p>Devices that support the PRIVATE_<wbr/>REPROCESSING capability or the
-YUV_<wbr/>REPROCESSING capability must support the
-CAMERA3_<wbr/>TEMPLATE_<wbr/>ZERO_<wbr/>SHUTTER_<wbr/>LAG template defined in camera3.<wbr/>h.<wbr/></p>
-<p>For DEPTH_<wbr/>OUTPUT,<wbr/> the depth-format keys
-<a href="#static_android.depth.availableDepthStreamConfigurations">android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stream<wbr/>Configurations</a>,<wbr/>
-<a href="#static_android.depth.availableDepthMinFrameDurations">android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Min<wbr/>Frame<wbr/>Durations</a>,<wbr/>
-<a href="#static_android.depth.availableDepthStallDurations">android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stall<wbr/>Durations</a> must be available,<wbr/> in
-addition to the other keys explicitly mentioned in the DEPTH_<wbr/>OUTPUT
-enum notes.<wbr/> The entry <a href="#static_android.depth.maxDepthSamples">android.<wbr/>depth.<wbr/>max<wbr/>Depth<wbr/>Samples</a> must be available
-if the DEPTH_<wbr/>POINT_<wbr/>CLOUD format is supported (HAL pixel format BLOB,<wbr/> dataspace
-DEPTH).<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.availableRequestKeys">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>request.<wbr/>available<wbr/>Request<wbr/>Keys
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A list of all keys that the camera device has available
-to use with <a href="https://developer.android.com/reference/android/hardware/camera2/CaptureRequest.html">CaptureRequest</a>.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Attempting to set a key into a CaptureRequest that is not
-listed here will result in an invalid request and will be rejected
-by the camera device.<wbr/></p>
-<p>This field can be used to query the feature set of a camera device
-at a more granular level than capabilities.<wbr/> This is especially
-important for optional keys that are not listed under any capability
-in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Vendor tags must not be listed here.<wbr/> Use the vendor tag metadata
-extensions C api instead (refer to camera3.<wbr/>h for more details).<wbr/></p>
-<p>Setting/<wbr/>getting vendor tags will be checked against the metadata
-vendor extensions API and not against this field.<wbr/></p>
-<p>The HAL must not consume any request tags that are not listed either
-here or in the vendor tag list.<wbr/></p>
-<p>The public camera2 API will always make the vendor tags visible
-via
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureRequestKeys">CameraCharacteristics#getAvailableCaptureRequestKeys</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.availableResultKeys">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>request.<wbr/>available<wbr/>Result<wbr/>Keys
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A list of all keys that the camera device has available
-to use with <a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html">CaptureResult</a>.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Attempting to get a key from a CaptureResult that is not
-listed here will always return a <code>null</code> value.<wbr/> Getting a key from
-a CaptureResult that is listed here will generally never return a <code>null</code>
-value.<wbr/></p>
-<p>The following keys may return <code>null</code> unless they are enabled:</p>
-<ul>
-<li><a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> (non-null iff <a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> == ON)</li>
-</ul>
-<p>(Those sometimes-null keys will nevertheless be listed here
-if they are available.<wbr/>)</p>
-<p>This field can be used to query the feature set of a camera device
-at a more granular level than capabilities.<wbr/> This is especially
-important for optional keys that are not listed under any capability
-in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Tags listed here must always have an entry in the result metadata,<wbr/>
-even if that size is 0 elements.<wbr/> Only array-type tags (e.<wbr/>g.<wbr/> lists,<wbr/>
-matrices,<wbr/> strings) are allowed to have 0 elements.<wbr/></p>
-<p>Vendor tags must not be listed here.<wbr/> Use the vendor tag metadata
-extensions C api instead (refer to camera3.<wbr/>h for more details).<wbr/></p>
-<p>Setting/<wbr/>getting vendor tags will be checked against the metadata
-vendor extensions API and not against this field.<wbr/></p>
-<p>The HAL must not produce any result tags that are not listed either
-here or in the vendor tag list.<wbr/></p>
-<p>The public camera2 API will always make the vendor tags visible via <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureResultKeys">CameraCharacteristics#getAvailableCaptureResultKeys</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.request.availableCharacteristicsKeys">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>request.<wbr/>available<wbr/>Characteristics<wbr/>Keys
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A list of all keys that the camera device has available
-to use with <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a>.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This entry follows the same rules as
-<a href="#static_android.request.availableResultKeys">android.<wbr/>request.<wbr/>available<wbr/>Result<wbr/>Keys</a> (except that it applies for
-CameraCharacteristics instead of CaptureResult).<wbr/> See above for more
-details.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Keys listed here must always have an entry in the static info metadata,<wbr/>
-even if that size is 0 elements.<wbr/> Only array-type tags (e.<wbr/>g.<wbr/> lists,<wbr/>
-matrices,<wbr/> strings) are allowed to have 0 elements.<wbr/></p>
-<p>Vendor tags must not be listed here.<wbr/> Use the vendor tag metadata
-extensions C api instead (refer to camera3.<wbr/>h for more details).<wbr/></p>
-<p>Setting/<wbr/>getting vendor tags will be checked against the metadata
-vendor extensions API and not against this field.<wbr/></p>
-<p>The HAL must not have any tags in its static info that are not listed
-either here or in the vendor tag list.<wbr/></p>
-<p>The public camera2 API will always make the vendor tags visible
-via <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getKeys">CameraCharacteristics#getKeys</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.request.frameCount">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>request.<wbr/>frame<wbr/>Count
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [hidden]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A frame counter set by the framework.<wbr/> This value monotonically
-increases with every new result (that is,<wbr/> each new result has a unique
-frameCount value).<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              count of frames
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-              <p>&gt; 0</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Reset on release()</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.request.id">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>request.<wbr/>id
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [hidden]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>An application-specified ID for the current
-request.<wbr/> Must be maintained unchanged in output
-frame</p>
-            </td>
-
-            <td class="entry_units">
-              arbitrary integer assigned by application
-            </td>
-
-            <td class="entry_range">
-              <p>Any int</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.request.metadataMode">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>request.<wbr/>metadata<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">NONE</span>
-                    <span class="entry_type_enum_notes"><p>No metadata should be produced on output,<wbr/> except
-for application-bound buffer data.<wbr/> If no
-application-bound streams exist,<wbr/> no frame should be
-placed in the output frame queue.<wbr/> If such streams
-exist,<wbr/> a frame should be placed on the output queue
-with null metadata but with the necessary output buffer
-information.<wbr/> Timestamp information should still be
-included with any output stream buffers</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FULL</span>
-                    <span class="entry_type_enum_notes"><p>All metadata should be produced.<wbr/> Statistics will
-only be produced if they are separately
-enabled</p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>How much metadata to produce on
-output</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.request.outputStreams">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>request.<wbr/>output<wbr/>Streams
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Lists which camera output streams image data
-from this capture must be sent to</p>
-            </td>
-
-            <td class="entry_units">
-              List of camera stream IDs
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-              <p>List must only include streams that have been
-created</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_HAL2">HAL2</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If no output streams are listed,<wbr/> then the image
-data should simply be discarded.<wbr/> The image data must
-still be captured for metadata and statistics production,<wbr/>
-and the lens and flash must operate as requested.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.request.pipelineDepth">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>request.<wbr/>pipeline<wbr/>Depth
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Specifies the number of pipeline stages the frame went
-through from when it was exposed to when the final completed result
-was available to the framework.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&lt;= <a href="#static_android.request.pipelineMaxDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Depending on what settings are used in the request,<wbr/> and
-what streams are configured,<wbr/> the data may undergo less processing,<wbr/>
-and some pipeline stages skipped.<wbr/></p>
-<p>See <a href="#static_android.request.pipelineMaxDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth</a> for more details.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This value must always represent the accurate count of how many
-pipeline stages were actually used.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_scaler" class="section">scaler</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.scaler.cropRegion">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>scaler.<wbr/>crop<wbr/>Region
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public as rectangle]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired region of the sensor to read out for this capture.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixel coordinates relative to
-          android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control can be used to implement digital zoom.<wbr/></p>
-<p>The crop region coordinate system is based off
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with <code>(0,<wbr/> 0)</code> being the
-top-left corner of the sensor active array.<wbr/></p>
-<p>Output streams use this rectangle to produce their output,<wbr/>
-cropping to a smaller region if necessary to maintain the
-stream's aspect ratio,<wbr/> then scaling the sensor input to
-match the output's configured resolution.<wbr/></p>
-<p>The crop region is applied after the RAW to other color
-space (e.<wbr/>g.<wbr/> YUV) conversion.<wbr/> Since raw streams
-(e.<wbr/>g.<wbr/> RAW16) don't have the conversion stage,<wbr/> they are not
-croppable.<wbr/> The crop region will be ignored by raw streams.<wbr/></p>
-<p>For non-raw streams,<wbr/> any additional per-stream cropping will
-be done to maximize the final pixel area of the stream.<wbr/></p>
-<p>For example,<wbr/> if the crop region is set to a 4:3 aspect
-ratio,<wbr/> then 4:3 streams will use the exact crop
-region.<wbr/> 16:9 streams will further crop vertically
-(letterbox).<wbr/></p>
-<p>Conversely,<wbr/> if the crop region is set to a 16:9,<wbr/> then 4:3
-outputs will crop horizontally (pillarbox),<wbr/> and 16:9
-streams will match exactly.<wbr/> These additional crops will
-be centered within the crop region.<wbr/></p>
-<p>The width and height of the crop region cannot
-be set to be smaller than
-<code>floor( activeArraySize.<wbr/>width /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code> and
-<code>floor( activeArraySize.<wbr/>height /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code>,<wbr/> respectively.<wbr/></p>
-<p>The camera device may adjust the crop region to account
-for rounding and other hardware requirements; the final
-crop region used will be included in the output capture
-result.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The output streams must maintain square pixels at all
-times,<wbr/> no matter what the relative aspect ratios of the
-crop region and the stream are.<wbr/>  Negative values for
-corner are allowed for raw output if full pixel array is
-larger than active pixel array.<wbr/> Width and height may be
-rounded to nearest larger supportable width,<wbr/> especially
-for raw output,<wbr/> where only a few fixed scales may be
-possible.<wbr/></p>
-<p>For a set of output streams configured,<wbr/> if the sensor output is cropped to a smaller
-size than active array size,<wbr/> the HAL need follow below cropping rules:</p>
-<ul>
-<li>
-<p>The HAL need handle the cropRegion as if the sensor crop size is the effective active
-array size.<wbr/>More specifically,<wbr/> the HAL must transform the request cropRegion from
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> to the sensor cropped pixel area size in this way:</p>
-<ol>
-<li>Translate the requested cropRegion w.<wbr/>r.<wbr/>t.,<wbr/> the left top corner of the sensor
-cropped pixel area by (tx,<wbr/> ty),<wbr/>
-where <code>tx = sensorCrop.<wbr/>top * (sensorCrop.<wbr/>height /<wbr/> activeArraySize.<wbr/>height)</code>
-and <code>tx = sensorCrop.<wbr/>left * (sensorCrop.<wbr/>width /<wbr/> activeArraySize.<wbr/>width)</code>.<wbr/> The
-(sensorCrop.<wbr/>top,<wbr/> sensorCrop.<wbr/>left) is the coordinate based off the
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></li>
-<li>Scale the width and height of requested cropRegion with scaling factor of
-sensor<wbr/>Crop.<wbr/>width/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>width and sensor<wbr/>Crop.<wbr/>height/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>height
-respectively.<wbr/>
-Once this new cropRegion is calculated,<wbr/> the HAL must use this region to crop the image
-with regard to the sensor crop size (effective active array size).<wbr/> The HAL still need
-follow the general cropping rule for this new cropRegion and effective active
-array size.<wbr/></li>
-</ol>
-</li>
-<li>
-<p>The HAL must report the cropRegion with regard to <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>
-The HAL need convert the new cropRegion generated above w.<wbr/>r.<wbr/>t.,<wbr/> full active array size.<wbr/>
-The reported cropRegion may be slightly different with the requested cropRegion since
-the HAL may adjust the crop region to account for rounding,<wbr/> conversion error,<wbr/> or other
-hardware limitations.<wbr/></p>
-</li>
-</ul>
-<p>HAL2.<wbr/>x uses only (x,<wbr/> y,<wbr/> width)</p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.scaler.availableFormats">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="5">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Formats
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [hidden as imageFormat]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">RAW16</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_value">0x20</span>
-                    <span class="entry_type_enum_notes"><p>RAW16 is a standard,<wbr/> cross-platform format for raw image
-buffers with 16-bit pixels.<wbr/></p>
-<p>Buffers of this format are typically expected to have a
-Bayer Color Filter Array (CFA) layout,<wbr/> which is given in
-<a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>.<wbr/> Sensors with
-CFAs that are not representable by a format in
-<a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a> should not
-use this format.<wbr/></p>
-<p>Buffers of this format will also follow the constraints given for
-RAW_<wbr/>OPAQUE buffers,<wbr/> but with relaxed performance constraints.<wbr/></p>
-<p>This format is intended to give users access to the full contents
-of the buffers coming directly from the image sensor prior to any
-cropping or scaling operations,<wbr/> and all coordinate systems for
-metadata used for this format are relative to the size of the
-active region of the image sensor before any geometric distortion
-correction has been applied (i.<wbr/>e.<wbr/>
-<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>).<wbr/> Supported
-dimensions for this format are limited to the full dimensions of
-the sensor (e.<wbr/>g.<wbr/> either <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a> or
-<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> will be the
-only supported output size).<wbr/></p>
-<p>See <a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a> for
-the full set of performance guarantees.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">RAW_OPAQUE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_value">0x24</span>
-                    <span class="entry_type_enum_notes"><p>RAW_<wbr/>OPAQUE (or
-<a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_PRIVATE">RAW_<wbr/>PRIVATE</a>
-as referred in public API) is a format for raw image buffers
-coming from an image sensor.<wbr/></p>
-<p>The actual structure of buffers of this format is
-platform-specific,<wbr/> but must follow several constraints:</p>
-<ol>
-<li>No image post-processing operations may have been applied to
-buffers of this type.<wbr/> These buffers contain raw image data coming
-directly from the image sensor.<wbr/></li>
-<li>If a buffer of this format is passed to the camera device for
-reprocessing,<wbr/> the resulting images will be identical to the images
-produced if the buffer had come directly from the sensor and was
-processed with the same settings.<wbr/></li>
-</ol>
-<p>The intended use for this format is to allow access to the native
-raw format buffers coming directly from the camera sensor without
-any additional conversions or decrease in framerate.<wbr/></p>
-<p>See <a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a> for the full set of
-performance guarantees.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">YV12</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_value">0x32315659</span>
-                    <span class="entry_type_enum_notes"><p>YCrCb 4:2:0 Planar</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">YCrCb_420_SP</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_value">0x11</span>
-                    <span class="entry_type_enum_notes"><p>NV21</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">IMPLEMENTATION_DEFINED</span>
-                    <span class="entry_type_enum_value">0x22</span>
-                    <span class="entry_type_enum_notes"><p>System internal format,<wbr/> not application-accessible</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">YCbCr_420_888</span>
-                    <span class="entry_type_enum_value">0x23</span>
-                    <span class="entry_type_enum_notes"><p>Flexible YUV420 Format</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">BLOB</span>
-                    <span class="entry_type_enum_value">0x21</span>
-                    <span class="entry_type_enum_notes"><p>JPEG format</p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The list of image formats that are supported by this
-camera device for output streams.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>All camera devices will support JPEG and YUV_<wbr/>420_<wbr/>888 formats.<wbr/></p>
-<p>When set to YUV_<wbr/>420_<wbr/>888,<wbr/> application can access the YUV420 data directly.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>These format values are from HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>* in
-system/<wbr/>core/<wbr/>include/<wbr/>system/<wbr/>graphics.<wbr/>h.<wbr/></p>
-<p>When IMPLEMENTATION_<wbr/>DEFINED is used,<wbr/> the platform
-gralloc module will select a format based on the usage flags provided
-by the camera HAL device and the other endpoint of the stream.<wbr/> It is
-usually used by preview and recording streams,<wbr/> where the application doesn't
-need access the image data.<wbr/></p>
-<p>YCb<wbr/>Cr_<wbr/>420_<wbr/>888 format must be supported by the HAL.<wbr/> When an image stream
-needs CPU/<wbr/>application direct access,<wbr/> this format will be used.<wbr/></p>
-<p>The BLOB format must be supported by the HAL.<wbr/> This is used for the JPEG stream.<wbr/></p>
-<p>A RAW_<wbr/>OPAQUE buffer should contain only pixel data.<wbr/> It is strongly
-recommended that any information used by the camera device when
-processing images is fully expressed by the result metadata
-for that image buffer.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableJpegMinDurations">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Min<wbr/>Durations
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [hidden]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The minimum frame duration that is supported
-for each resolution in <a href="#static_android.scaler.availableJpegSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Sizes</a>.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-              <p>TODO: Remove property.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This corresponds to the minimum steady-state frame duration when only
-that JPEG stream is active and captured in a burst,<wbr/> with all
-processing (typically in android.<wbr/>*.<wbr/>mode) set to FAST.<wbr/></p>
-<p>When multiple streams are configured,<wbr/> the minimum
-frame duration will be &gt;= max(individual stream min
-durations)</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableJpegSizes">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="5">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Sizes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 2
-                </span>
-              <span class="entry_type_visibility"> [hidden as size]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The JPEG resolutions that are supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-              <p>TODO: Remove property.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The resolutions are listed as <code>(width,<wbr/> height)</code> pairs.<wbr/> All camera devices will support
-sensor maximum resolution (defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>).<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL must include sensor maximum resolution
-(defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>),<wbr/>
-and should include half/<wbr/>quarter of sensor maximum resolution.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableMaxDigitalZoom">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum ratio between both active area width
-and crop region width,<wbr/> and active area height and
-crop region height,<wbr/> for <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Zoom scale factor
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;=1</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This represents the maximum amount of zooming possible by
-the camera device,<wbr/> or equivalently,<wbr/> the minimum cropping
-window size.<wbr/></p>
-<p>Crop regions that have a width or height that is smaller
-than this ratio allows will be rounded up to the minimum
-allowed size by the camera device.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableProcessedMinDurations">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Processed<wbr/>Min<wbr/>Durations
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [hidden]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>For each available processed output size (defined in
-<a href="#static_android.scaler.availableProcessedSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Processed<wbr/>Sizes</a>),<wbr/> this property lists the
-minimum supportable frame duration for that size.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This should correspond to the frame duration when only that processed
-stream is active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode)
-set to FAST.<wbr/></p>
-<p>When multiple streams are configured,<wbr/> the minimum frame duration will
-be &gt;= max(individual stream min durations).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableProcessedSizes">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="5">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Processed<wbr/>Sizes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 2
-                </span>
-              <span class="entry_type_visibility"> [hidden as size]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The resolutions available for use with
-processed output streams,<wbr/> such as YV12,<wbr/> NV12,<wbr/> and
-platform opaque YUV/<wbr/>RGB streams to the GPU or video
-encoders.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The resolutions are listed as <code>(width,<wbr/> height)</code> pairs.<wbr/></p>
-<p>For a given use case,<wbr/> the actual maximum supported resolution
-may be lower than what is listed here,<wbr/> depending on the destination
-Surface for the image data.<wbr/> For example,<wbr/> for recording video,<wbr/>
-the video encoder chosen may have a maximum size limit (e.<wbr/>g.<wbr/> 1080p)
-smaller than what the camera (e.<wbr/>g.<wbr/> maximum resolution is 3264x2448)
-can provide.<wbr/></p>
-<p>Please reference the documentation for the image data destination to
-check if it limits the maximum size for image data.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For FULL capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>),<wbr/>
-the HAL must include all JPEG sizes listed in <a href="#static_android.scaler.availableJpegSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Jpeg<wbr/>Sizes</a>
-and each below resolution if it is smaller than or equal to the sensor
-maximum resolution (if they are not listed in JPEG sizes already):</p>
-<ul>
-<li>240p (320 x 240)</li>
-<li>480p (640 x 480)</li>
-<li>720p (1280 x 720)</li>
-<li>1080p (1920 x 1080)</li>
-</ul>
-<p>For LIMITED capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>),<wbr/>
-the HAL only has to list up to the maximum video size supported by the devices.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableRawMinDurations">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Raw<wbr/>Min<wbr/>Durations
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>For each available raw output size (defined in
-<a href="#static_android.scaler.availableRawSizes">android.<wbr/>scaler.<wbr/>available<wbr/>Raw<wbr/>Sizes</a>),<wbr/> this property lists the minimum
-supportable frame duration for that size.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Should correspond to the frame duration when only the raw stream is
-active.<wbr/></p>
-<p>When multiple streams are configured,<wbr/> the minimum
-frame duration will be &gt;= max(individual stream min
-durations)</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableRawSizes">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="1">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Raw<wbr/>Sizes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 2
-                </span>
-              <span class="entry_type_visibility"> [system as size]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The resolutions available for use with raw
-sensor output streams,<wbr/> listed as width,<wbr/>
-height</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableInputOutputFormatsMap">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [hidden as reprocessFormatsMap]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The mapping of image formats that are supported by this
-camera device for input streams,<wbr/> to their corresponding output formats.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>All camera devices with at least 1
-<a href="#static_android.request.maxNumInputStreams">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Input<wbr/>Streams</a> will have at least one
-available input format.<wbr/></p>
-<p>The camera device will support the following map of formats,<wbr/>
-if its dependent capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>) is supported:</p>
-<table>
-<thead>
-<tr>
-<th align="left">Input Format</th>
-<th align="left">Output Format</th>
-<th align="left">Capability</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a></td>
-<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
-<td align="left">PRIVATE_<wbr/>REPROCESSING</td>
-</tr>
-<tr>
-<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a></td>
-<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
-<td align="left">PRIVATE_<wbr/>REPROCESSING</td>
-</tr>
-<tr>
-<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
-<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
-<td align="left">YUV_<wbr/>REPROCESSING</td>
-</tr>
-<tr>
-<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
-<td align="left"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
-<td align="left">YUV_<wbr/>REPROCESSING</td>
-</tr>
-</tbody>
-</table>
-<p>PRIVATE refers to a device-internal format that is not directly application-visible.<wbr/>  A
-PRIVATE input surface can be acquired by <a href="https://developer.android.com/reference/android/media/ImageReader.html#newInstance">ImageReader#newInstance</a>
-with <a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a> as the format.<wbr/></p>
-<p>For a PRIVATE_<wbr/>REPROCESSING-capable camera device,<wbr/> using the PRIVATE format as either input
-or output will never hurt maximum frame rate (i.<wbr/>e.<wbr/>  <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">getOutputStallDuration(ImageFormat.<wbr/>PRIVATE,<wbr/> size)</a> is always 0),<wbr/></p>
-<p>Attempting to configure an input stream with output streams not
-listed as available in this map is not valid.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For the formats,<wbr/> see <code>system/<wbr/>core/<wbr/>include/<wbr/>system/<wbr/>graphics.<wbr/>h</code> for a definition
-of the image format enumerations.<wbr/> The PRIVATE format refers to the
-HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>IMPLEMENTATION_<wbr/>DEFINED format.<wbr/> The HAL could determine
-the actual format by using the gralloc usage flags.<wbr/>
-For ZSL use case in particular,<wbr/> the HAL could choose appropriate format (partially
-processed YUV or RAW based format) by checking the format and GRALLOC_<wbr/>USAGE_<wbr/>HW_<wbr/>CAMERA_<wbr/>ZSL.<wbr/>
-See camera3.<wbr/>h for more details.<wbr/></p>
-<p>This value is encoded as a variable-size array-of-arrays.<wbr/>
-The inner array always contains <code>[format,<wbr/> length,<wbr/> ...<wbr/>]</code> where
-<code>...<wbr/></code> has <code>length</code> elements.<wbr/> An inner array is followed by another
-inner array if the total metadata entry size hasn't yet been exceeded.<wbr/></p>
-<p>A code sample to read/<wbr/>write this encoding (with a device that
-supports reprocessing IMPLEMENTATION_<wbr/>DEFINED to YUV_<wbr/>420_<wbr/>888,<wbr/> and JPEG,<wbr/>
-and reprocessing YUV_<wbr/>420_<wbr/>888 to YUV_<wbr/>420_<wbr/>888 and JPEG):</p>
-<pre><code>//<wbr/> reading
-int32_<wbr/>t* contents = &amp;entry.<wbr/>i32[0];
-for (size_<wbr/>t i = 0; i &lt; entry.<wbr/>count; ) {
-    int32_<wbr/>t format = contents[i++];
-    int32_<wbr/>t length = contents[i++];
-    int32_<wbr/>t output_<wbr/>formats[length];
-    memcpy(&amp;output_<wbr/>formats[0],<wbr/> &amp;contents[i],<wbr/>
-           length * sizeof(int32_<wbr/>t));
-    i += length;
-}
-
-//<wbr/> writing (static example,<wbr/> PRIVATE_<wbr/>REPROCESSING + YUV_<wbr/>REPROCESSING)
-int32_<wbr/>t[] contents = {
-  IMPLEMENTATION_<wbr/>DEFINED,<wbr/> 2,<wbr/> YUV_<wbr/>420_<wbr/>888,<wbr/> BLOB,<wbr/>
-  YUV_<wbr/>420_<wbr/>888,<wbr/> 2,<wbr/> YUV_<wbr/>420_<wbr/>888,<wbr/> BLOB,<wbr/>
-};
-update_<wbr/>camera_<wbr/>metadata_<wbr/>entry(metadata,<wbr/> index,<wbr/> &amp;contents[0],<wbr/>
-      sizeof(contents)/<wbr/>sizeof(contents[0]),<wbr/> &amp;updated_<wbr/>entry);
-</code></pre>
-<p>If the HAL claims to support any of the capabilities listed in the
-above details,<wbr/> then it must also support all the input-output
-combinations listed for that capability.<wbr/> It can optionally support
-additional formats if it so chooses.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableStreamConfigurations">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 4
-                </span>
-              <span class="entry_type_visibility"> [ndk_public as streamConfiguration]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OUTPUT</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">INPUT</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The available stream configurations that this
-camera device supports
-(i.<wbr/>e.<wbr/> format,<wbr/> width,<wbr/> height,<wbr/> output/<wbr/>input stream).<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The configurations are listed as <code>(format,<wbr/> width,<wbr/> height,<wbr/> input?)</code>
-tuples.<wbr/></p>
-<p>For a given use case,<wbr/> the actual maximum supported resolution
-may be lower than what is listed here,<wbr/> depending on the destination
-Surface for the image data.<wbr/> For example,<wbr/> for recording video,<wbr/>
-the video encoder chosen may have a maximum size limit (e.<wbr/>g.<wbr/> 1080p)
-smaller than what the camera (e.<wbr/>g.<wbr/> maximum resolution is 3264x2448)
-can provide.<wbr/></p>
-<p>Please reference the documentation for the image data destination to
-check if it limits the maximum size for image data.<wbr/></p>
-<p>Not all output formats may be supported in a configuration with
-an input stream of a particular format.<wbr/> For more details,<wbr/> see
-<a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a>.<wbr/></p>
-<p>The following table describes the minimum required output stream
-configurations based on the hardware level
-(<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a>):</p>
-<table>
-<thead>
-<tr>
-<th align="center">Format</th>
-<th align="center">Size</th>
-<th align="center">Hardware Level</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">JPEG</td>
-<td align="center"><a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a></td>
-<td align="center">Any</td>
-<td align="center"></td>
-</tr>
-<tr>
-<td align="center">JPEG</td>
-<td align="center">1920x1080 (1080p)</td>
-<td align="center">Any</td>
-<td align="center">if 1080p &lt;= activeArraySize</td>
-</tr>
-<tr>
-<td align="center">JPEG</td>
-<td align="center">1280x720 (720)</td>
-<td align="center">Any</td>
-<td align="center">if 720p &lt;= activeArraySize</td>
-</tr>
-<tr>
-<td align="center">JPEG</td>
-<td align="center">640x480 (480p)</td>
-<td align="center">Any</td>
-<td align="center">if 480p &lt;= activeArraySize</td>
-</tr>
-<tr>
-<td align="center">JPEG</td>
-<td align="center">320x240 (240p)</td>
-<td align="center">Any</td>
-<td align="center">if 240p &lt;= activeArraySize</td>
-</tr>
-<tr>
-<td align="center">YUV_<wbr/>420_<wbr/>888</td>
-<td align="center">all output sizes available for JPEG</td>
-<td align="center">FULL</td>
-<td align="center"></td>
-</tr>
-<tr>
-<td align="center">YUV_<wbr/>420_<wbr/>888</td>
-<td align="center">all output sizes available for JPEG,<wbr/> up to the maximum video size</td>
-<td align="center">LIMITED</td>
-<td align="center"></td>
-</tr>
-<tr>
-<td align="center">IMPLEMENTATION_<wbr/>DEFINED</td>
-<td align="center">same as YUV_<wbr/>420_<wbr/>888</td>
-<td align="center">Any</td>
-<td align="center"></td>
-</tr>
-</tbody>
-</table>
-<p>Refer to <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> for additional
-mandatory stream configurations on a per-capability basis.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>It is recommended (but not mandatory) to also include half/<wbr/>quarter
-of sensor maximum resolution for JPEG formats (regardless of hardware
-level).<wbr/></p>
-<p>(The following is a rewording of the above required table):</p>
-<p>For JPEG format,<wbr/> the sizes may be restricted by below conditions:</p>
-<ul>
-<li>The HAL may choose the aspect ratio of each Jpeg size to be one of well known ones
-(e.<wbr/>g.<wbr/> 4:3,<wbr/> 16:9,<wbr/> 3:2 etc.<wbr/>).<wbr/> If the sensor maximum resolution
-(defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>) has an aspect ratio other than these,<wbr/>
-it does not have to be included in the supported JPEG sizes.<wbr/></li>
-<li>Some hardware JPEG encoders may have pixel boundary alignment requirements,<wbr/> such as
-the dimensions being a multiple of 16.<wbr/></li>
-</ul>
-<p>Therefore,<wbr/> the maximum JPEG size may be smaller than sensor maximum resolution.<wbr/>
-However,<wbr/> the largest JPEG size must be as close as possible to the sensor maximum
-resolution given above constraints.<wbr/> It is required that after aspect ratio adjustments,<wbr/>
-additional size reduction due to other issues must be less than 3% in area.<wbr/> For example,<wbr/>
-if the sensor maximum resolution is 3280x2464,<wbr/> if the maximum JPEG size has aspect
-ratio 4:3,<wbr/> the JPEG encoder alignment requirement is 16,<wbr/> the maximum JPEG size will be
-3264x2448.<wbr/></p>
-<p>For FULL capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>),<wbr/>
-the HAL must include all YUV_<wbr/>420_<wbr/>888 sizes that have JPEG sizes listed
-here as output streams.<wbr/></p>
-<p>It must also include each below resolution if it is smaller than or
-equal to the sensor maximum resolution (for both YUV_<wbr/>420_<wbr/>888 and JPEG
-formats),<wbr/> as output streams:</p>
-<ul>
-<li>240p (320 x 240)</li>
-<li>480p (640 x 480)</li>
-<li>720p (1280 x 720)</li>
-<li>1080p (1920 x 1080)</li>
-</ul>
-<p>For LIMITED capability devices
-(<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>),<wbr/>
-the HAL only has to list up to the maximum video size
-supported by the device.<wbr/></p>
-<p>Regardless of hardware level,<wbr/> every output resolution available for
-YUV_<wbr/>420_<wbr/>888 must also be available for IMPLEMENTATION_<wbr/>DEFINED.<wbr/></p>
-<p>This supercedes the following fields,<wbr/> which are now deprecated:</p>
-<ul>
-<li>availableFormats</li>
-<li>available[Processed,<wbr/>Raw,<wbr/>Jpeg]Sizes</li>
-</ul>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableMinFrameDurations">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Min<wbr/>Frame<wbr/>Durations
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4 x n
-                </span>
-              <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>This lists the minimum frame duration for each
-format/<wbr/>size combination.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This should correspond to the frame duration when only that
-stream is active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode)
-set to either OFF or FAST.<wbr/></p>
-<p>When multiple streams are used in a request,<wbr/> the minimum frame
-duration will be max(individual stream min durations).<wbr/></p>
-<p>The minimum frame duration of a stream (of a particular format,<wbr/> size)
-is the same regardless of whether the stream is input or output.<wbr/></p>
-<p>See <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> and
-<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a> for more details about
-calculating the max frame rate.<wbr/></p>
-<p>(Keep in sync with
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>)</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.availableStallDurations">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4 x n
-                </span>
-              <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>This lists the maximum stall duration for each
-output format/<wbr/>size combination.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>A stall duration is how much extra time would get added
-to the normal minimum frame duration for a repeating request
-that has streams with non-zero stall.<wbr/></p>
-<p>For example,<wbr/> consider JPEG captures which have the following
-characteristics:</p>
-<ul>
-<li>JPEG streams act like processed YUV streams in requests for which
-they are not included; in requests in which they are directly
-referenced,<wbr/> they act as JPEG streams.<wbr/> This is because supporting a
-JPEG stream requires the underlying YUV data to always be ready for
-use by a JPEG encoder,<wbr/> but the encoder will only be used (and impact
-frame duration) on requests that actually reference a JPEG stream.<wbr/></li>
-<li>The JPEG processor can run concurrently to the rest of the camera
-pipeline,<wbr/> but cannot process more than 1 capture at a time.<wbr/></li>
-</ul>
-<p>In other words,<wbr/> using a repeating YUV request would result
-in a steady frame rate (let's say it's 30 FPS).<wbr/> If a single
-JPEG request is submitted periodically,<wbr/> the frame rate will stay
-at 30 FPS (as long as we wait for the previous JPEG to return each
-time).<wbr/> If we try to submit a repeating YUV + JPEG request,<wbr/> then
-the frame rate will drop from 30 FPS.<wbr/></p>
-<p>In general,<wbr/> submitting a new request with a non-0 stall time
-stream will <em>not</em> cause a frame rate drop unless there are still
-outstanding buffers for that stream from previous requests.<wbr/></p>
-<p>Submitting a repeating request with streams (call this <code>S</code>)
-is the same as setting the minimum frame duration from
-the normal minimum frame duration corresponding to <code>S</code>,<wbr/> added with
-the maximum stall duration for <code>S</code>.<wbr/></p>
-<p>If interleaving requests with and without a stall duration,<wbr/>
-a request will stall by the maximum of the remaining times
-for each can-stall stream with outstanding buffers.<wbr/></p>
-<p>This means that a stalling request will not have an exposure start
-until the stall has completed.<wbr/></p>
-<p>This should correspond to the stall duration when only that stream is
-active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode) set to FAST
-or OFF.<wbr/> Setting any of the processing modes to HIGH_<wbr/>QUALITY
-effectively results in an indeterminate stall duration for all
-streams in a request (the regular stall calculation rules are
-ignored).<wbr/></p>
-<p>The following formats may always have a stall duration:</p>
-<ul>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW_SENSOR">ImageFormat#RAW_<wbr/>SENSOR</a></li>
-</ul>
-<p>The following formats will never have a stall duration:</p>
-<ul>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></li>
-<li><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#RAW10">ImageFormat#RAW10</a></li>
-</ul>
-<p>All other formats may or may not have an allowed stall duration on
-a per-capability basis; refer to <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>
-for more details.<wbr/></p>
-<p>See <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> for more information about
-calculating the max frame rate (absent stalls).<wbr/></p>
-<p>(Keep up to date with
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a> )</p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If possible,<wbr/> it is recommended that all non-JPEG formats
-(such as RAW16) should not have a stall duration.<wbr/> RAW10,<wbr/> RAW12,<wbr/> RAW_<wbr/>OPAQUE
-and IMPLEMENTATION_<wbr/>DEFINED must not have stall durations.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.streamConfigurationMap">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [java_public as streamConfigurationMap]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The available stream configurations that this
-camera device supports; also includes the minimum frame durations
-and the stall durations for each format/<wbr/>size combination.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>All camera devices will support sensor maximum resolution (defined by
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>) for the JPEG format.<wbr/></p>
-<p>For a given use case,<wbr/> the actual maximum supported resolution
-may be lower than what is listed here,<wbr/> depending on the destination
-Surface for the image data.<wbr/> For example,<wbr/> for recording video,<wbr/>
-the video encoder chosen may have a maximum size limit (e.<wbr/>g.<wbr/> 1080p)
-smaller than what the camera (e.<wbr/>g.<wbr/> maximum resolution is 3264x2448)
-can provide.<wbr/></p>
-<p>Please reference the documentation for the image data destination to
-check if it limits the maximum size for image data.<wbr/></p>
-<p>The following table describes the minimum required output stream
-configurations based on the hardware level
-(<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a>):</p>
-<table>
-<thead>
-<tr>
-<th align="center">Format</th>
-<th align="center">Size</th>
-<th align="center">Hardware Level</th>
-<th align="center">Notes</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
-<td align="center"><a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> (*1)</td>
-<td align="center">Any</td>
-<td align="center"></td>
-</tr>
-<tr>
-<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
-<td align="center">1920x1080 (1080p)</td>
-<td align="center">Any</td>
-<td align="center">if 1080p &lt;= activeArraySize</td>
-</tr>
-<tr>
-<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
-<td align="center">1280x720 (720p)</td>
-<td align="center">Any</td>
-<td align="center">if 720p &lt;= activeArraySize</td>
-</tr>
-<tr>
-<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
-<td align="center">640x480 (480p)</td>
-<td align="center">Any</td>
-<td align="center">if 480p &lt;= activeArraySize</td>
-</tr>
-<tr>
-<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#JPEG">ImageFormat#JPEG</a></td>
-<td align="center">320x240 (240p)</td>
-<td align="center">Any</td>
-<td align="center">if 240p &lt;= activeArraySize</td>
-</tr>
-<tr>
-<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
-<td align="center">all output sizes available for JPEG</td>
-<td align="center">FULL</td>
-<td align="center"></td>
-</tr>
-<tr>
-<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#YUV_420_888">Image<wbr/>Format#YUV_<wbr/>420_<wbr/>888</a></td>
-<td align="center">all output sizes available for JPEG,<wbr/> up to the maximum video size</td>
-<td align="center">LIMITED</td>
-<td align="center"></td>
-</tr>
-<tr>
-<td align="center"><a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#PRIVATE">ImageFormat#PRIVATE</a></td>
-<td align="center">same as YUV_<wbr/>420_<wbr/>888</td>
-<td align="center">Any</td>
-<td align="center"></td>
-</tr>
-</tbody>
-</table>
-<p>Refer to <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> and <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">CameraDevice#createCaptureSession</a> for additional mandatory
-stream configurations on a per-capability basis.<wbr/></p>
-<p>*1: For JPEG format,<wbr/> the sizes may be restricted by below conditions:</p>
-<ul>
-<li>The HAL may choose the aspect ratio of each Jpeg size to be one of well known ones
-(e.<wbr/>g.<wbr/> 4:3,<wbr/> 16:9,<wbr/> 3:2 etc.<wbr/>).<wbr/> If the sensor maximum resolution
-(defined by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>) has an aspect ratio other than these,<wbr/>
-it does not have to be included in the supported JPEG sizes.<wbr/></li>
-<li>Some hardware JPEG encoders may have pixel boundary alignment requirements,<wbr/> such as
-the dimensions being a multiple of 16.<wbr/>
-Therefore,<wbr/> the maximum JPEG size may be smaller than sensor maximum resolution.<wbr/>
-However,<wbr/> the largest JPEG size will be as close as possible to the sensor maximum
-resolution given above constraints.<wbr/> It is required that after aspect ratio adjustments,<wbr/>
-additional size reduction due to other issues must be less than 3% in area.<wbr/> For example,<wbr/>
-if the sensor maximum resolution is 3280x2464,<wbr/> if the maximum JPEG size has aspect
-ratio 4:3,<wbr/> and the JPEG encoder alignment requirement is 16,<wbr/> the maximum JPEG size will be
-3264x2448.<wbr/></li>
-</ul>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Do not set this property directly
-(it is synthetic and will not be available at the HAL layer);
-set the <a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> instead.<wbr/></p>
-<p>Not all output formats may be supported in a configuration with
-an input stream of a particular format.<wbr/> For more details,<wbr/> see
-<a href="#static_android.scaler.availableInputOutputFormatsMap">android.<wbr/>scaler.<wbr/>available<wbr/>Input<wbr/>Output<wbr/>Formats<wbr/>Map</a>.<wbr/></p>
-<p>It is recommended (but not mandatory) to also include half/<wbr/>quarter
-of sensor maximum resolution for JPEG formats (regardless of hardware
-level).<wbr/></p>
-<p>(The following is a rewording of the above required table):</p>
-<p>The HAL must include sensor maximum resolution (defined by
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>).<wbr/></p>
-<p>For FULL capability devices (<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL</code>),<wbr/>
-the HAL must include all YUV_<wbr/>420_<wbr/>888 sizes that have JPEG sizes listed
-here as output streams.<wbr/></p>
-<p>It must also include each below resolution if it is smaller than or
-equal to the sensor maximum resolution (for both YUV_<wbr/>420_<wbr/>888 and JPEG
-formats),<wbr/> as output streams:</p>
-<ul>
-<li>240p (320 x 240)</li>
-<li>480p (640 x 480)</li>
-<li>720p (1280 x 720)</li>
-<li>1080p (1920 x 1080)</li>
-</ul>
-<p>For LIMITED capability devices
-(<code><a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == LIMITED</code>),<wbr/>
-the HAL only has to list up to the maximum video size
-supported by the device.<wbr/></p>
-<p>Regardless of hardware level,<wbr/> every output resolution available for
-YUV_<wbr/>420_<wbr/>888 must also be available for IMPLEMENTATION_<wbr/>DEFINED.<wbr/></p>
-<p>This supercedes the following fields,<wbr/> which are now deprecated:</p>
-<ul>
-<li>availableFormats</li>
-<li>available[Processed,<wbr/>Raw,<wbr/>Jpeg]Sizes</li>
-</ul>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.scaler.croppingType">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>scaler.<wbr/>cropping<wbr/>Type
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">CENTER_ONLY</span>
-                    <span class="entry_type_enum_notes"><p>The camera device only supports centered crop regions.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FREEFORM</span>
-                    <span class="entry_type_enum_notes"><p>The camera device supports arbitrarily chosen crop regions.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The crop type that this camera device supports.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When passing a non-centered crop region (<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>) to a camera
-device that only supports CENTER_<wbr/>ONLY cropping,<wbr/> the camera device will move the
-crop region to the center of the sensor active array (<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>)
-and keep the crop region width and height unchanged.<wbr/> The camera device will return the
-final used crop region in metadata result <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>.<wbr/></p>
-<p>Camera devices that support FREEFORM cropping will support any crop region that
-is inside of the active array.<wbr/> The camera device will apply the same crop region and
-return the final used crop region in capture result metadata <a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>.<wbr/></p>
-<p>LEGACY capability devices will only support CENTER_<wbr/>ONLY cropping.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.scaler.cropRegion">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>scaler.<wbr/>crop<wbr/>Region
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public as rectangle]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The desired region of the sensor to read out for this capture.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixel coordinates relative to
-          android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This control can be used to implement digital zoom.<wbr/></p>
-<p>The crop region coordinate system is based off
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with <code>(0,<wbr/> 0)</code> being the
-top-left corner of the sensor active array.<wbr/></p>
-<p>Output streams use this rectangle to produce their output,<wbr/>
-cropping to a smaller region if necessary to maintain the
-stream's aspect ratio,<wbr/> then scaling the sensor input to
-match the output's configured resolution.<wbr/></p>
-<p>The crop region is applied after the RAW to other color
-space (e.<wbr/>g.<wbr/> YUV) conversion.<wbr/> Since raw streams
-(e.<wbr/>g.<wbr/> RAW16) don't have the conversion stage,<wbr/> they are not
-croppable.<wbr/> The crop region will be ignored by raw streams.<wbr/></p>
-<p>For non-raw streams,<wbr/> any additional per-stream cropping will
-be done to maximize the final pixel area of the stream.<wbr/></p>
-<p>For example,<wbr/> if the crop region is set to a 4:3 aspect
-ratio,<wbr/> then 4:3 streams will use the exact crop
-region.<wbr/> 16:9 streams will further crop vertically
-(letterbox).<wbr/></p>
-<p>Conversely,<wbr/> if the crop region is set to a 16:9,<wbr/> then 4:3
-outputs will crop horizontally (pillarbox),<wbr/> and 16:9
-streams will match exactly.<wbr/> These additional crops will
-be centered within the crop region.<wbr/></p>
-<p>The width and height of the crop region cannot
-be set to be smaller than
-<code>floor( activeArraySize.<wbr/>width /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code> and
-<code>floor( activeArraySize.<wbr/>height /<wbr/> <a href="#static_android.scaler.availableMaxDigitalZoom">android.<wbr/>scaler.<wbr/>available<wbr/>Max<wbr/>Digital<wbr/>Zoom</a> )</code>,<wbr/> respectively.<wbr/></p>
-<p>The camera device may adjust the crop region to account
-for rounding and other hardware requirements; the final
-crop region used will be included in the output capture
-result.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The output streams must maintain square pixels at all
-times,<wbr/> no matter what the relative aspect ratios of the
-crop region and the stream are.<wbr/>  Negative values for
-corner are allowed for raw output if full pixel array is
-larger than active pixel array.<wbr/> Width and height may be
-rounded to nearest larger supportable width,<wbr/> especially
-for raw output,<wbr/> where only a few fixed scales may be
-possible.<wbr/></p>
-<p>For a set of output streams configured,<wbr/> if the sensor output is cropped to a smaller
-size than active array size,<wbr/> the HAL need follow below cropping rules:</p>
-<ul>
-<li>
-<p>The HAL need handle the cropRegion as if the sensor crop size is the effective active
-array size.<wbr/>More specifically,<wbr/> the HAL must transform the request cropRegion from
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> to the sensor cropped pixel area size in this way:</p>
-<ol>
-<li>Translate the requested cropRegion w.<wbr/>r.<wbr/>t.,<wbr/> the left top corner of the sensor
-cropped pixel area by (tx,<wbr/> ty),<wbr/>
-where <code>tx = sensorCrop.<wbr/>top * (sensorCrop.<wbr/>height /<wbr/> activeArraySize.<wbr/>height)</code>
-and <code>tx = sensorCrop.<wbr/>left * (sensorCrop.<wbr/>width /<wbr/> activeArraySize.<wbr/>width)</code>.<wbr/> The
-(sensorCrop.<wbr/>top,<wbr/> sensorCrop.<wbr/>left) is the coordinate based off the
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></li>
-<li>Scale the width and height of requested cropRegion with scaling factor of
-sensor<wbr/>Crop.<wbr/>width/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>width and sensor<wbr/>Crop.<wbr/>height/<wbr/>active<wbr/>Array<wbr/>Size.<wbr/>height
-respectively.<wbr/>
-Once this new cropRegion is calculated,<wbr/> the HAL must use this region to crop the image
-with regard to the sensor crop size (effective active array size).<wbr/> The HAL still need
-follow the general cropping rule for this new cropRegion and effective active
-array size.<wbr/></li>
-</ol>
-</li>
-<li>
-<p>The HAL must report the cropRegion with regard to <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/>
-The HAL need convert the new cropRegion generated above w.<wbr/>r.<wbr/>t.,<wbr/> full active array size.<wbr/>
-The reported cropRegion may be slightly different with the requested cropRegion since
-the HAL may adjust the crop region to account for rounding,<wbr/> conversion error,<wbr/> or other
-hardware limitations.<wbr/></p>
-</li>
-</ul>
-<p>HAL2.<wbr/>x uses only (x,<wbr/> y,<wbr/> width)</p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_sensor" class="section">sensor</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.sensor.exposureTime">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>exposure<wbr/>Time
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Duration each pixel is exposed to
-light.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If the sensor can't expose this exact duration,<wbr/> it will shorten the
-duration exposed to the nearest possible value (rather than expose longer).<wbr/>
-The final exposure time used will be available in the output capture result.<wbr/></p>
-<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
-OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.sensor.frameDuration">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>frame<wbr/>Duration
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Duration from start of frame exposure to
-start of next frame exposure.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p>See <a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a>,<wbr/>
-<a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/> The duration
-is capped to <code>max(duration,<wbr/> exposureTime + overhead)</code>.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The maximum frame rate that can be supported by a camera subsystem is
-a function of many factors:</p>
-<ul>
-<li>Requested resolutions of output image streams</li>
-<li>Availability of binning /<wbr/> skipping modes on the imager</li>
-<li>The bandwidth of the imager interface</li>
-<li>The bandwidth of the various ISP processing blocks</li>
-</ul>
-<p>Since these factors can vary greatly between different ISPs and
-sensors,<wbr/> the camera abstraction tries to represent the bandwidth
-restrictions with as simple a model as possible.<wbr/></p>
-<p>The model presented has the following characteristics:</p>
-<ul>
-<li>The image sensor is always configured to output the smallest
-resolution possible given the application's requested output stream
-sizes.<wbr/>  The smallest resolution is defined as being at least as large
-as the largest requested output stream size; the camera pipeline must
-never digitally upsample sensor data when the crop region covers the
-whole sensor.<wbr/> In general,<wbr/> this means that if only small output stream
-resolutions are configured,<wbr/> the sensor can provide a higher frame
-rate.<wbr/></li>
-<li>Since any request may use any or all the currently configured
-output streams,<wbr/> the sensor and ISP must be configured to support
-scaling a single capture to all the streams at the same time.<wbr/>  This
-means the camera pipeline must be ready to produce the largest
-requested output size without any delay.<wbr/>  Therefore,<wbr/> the overall
-frame rate of a given configured stream set is governed only by the
-largest requested stream resolution.<wbr/></li>
-<li>Using more than one output stream in a request does not affect the
-frame duration.<wbr/></li>
-<li>Certain format-streams may need to do additional background processing
-before data is consumed/<wbr/>produced by that stream.<wbr/> These processors
-can run concurrently to the rest of the camera pipeline,<wbr/> but
-cannot process more than 1 capture at a time.<wbr/></li>
-</ul>
-<p>The necessary information for the application,<wbr/> given the model above,<wbr/>
-is provided via the <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> field using
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>.<wbr/>
-These are used to determine the maximum frame rate /<wbr/> minimum frame
-duration that is possible for a given stream configuration.<wbr/></p>
-<p>Specifically,<wbr/> the application can use the following rules to
-determine the minimum frame duration it can request from the camera
-device:</p>
-<ol>
-<li>Let the set of currently configured input/<wbr/>output streams
-be called <code>S</code>.<wbr/></li>
-<li>Find the minimum frame durations for each stream in <code>S</code>,<wbr/> by looking
-it up in <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> using <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>
-(with its respective size/<wbr/>format).<wbr/> Let this set of frame durations be
-called <code>F</code>.<wbr/></li>
-<li>For any given request <code>R</code>,<wbr/> the minimum frame duration allowed
-for <code>R</code> is the maximum out of all values in <code>F</code>.<wbr/> Let the streams
-used in <code>R</code> be called <code>S_<wbr/>r</code>.<wbr/></li>
-</ol>
-<p>If none of the streams in <code>S_<wbr/>r</code> have a stall time (listed in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>
-using its respective size/<wbr/>format),<wbr/> then the frame duration in <code>F</code>
-determines the steady state frame rate that the application will get
-if it uses <code>R</code> as a repeating request.<wbr/> Let this special kind of
-request be called <code>Rsimple</code>.<wbr/></p>
-<p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
-by a single capture of a new request <code>Rstall</code> (which has at least
-one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
-same minimum frame duration this will not cause a frame rate loss
-if all buffers from the previous <code>Rstall</code> have already been
-delivered.<wbr/></p>
-<p>For more details about stalling,<wbr/> see
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>.<wbr/></p>
-<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
-OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For more details about stalling,<wbr/> see
-<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.sensor.sensitivity">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>sensitivity
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The amount of gain applied to sensor data
-before processing.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              ISO arithmetic units
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The sensitivity is the standard ISO sensitivity value,<wbr/>
-as defined in ISO 12232:2006.<wbr/></p>
-<p>The sensitivity must be within <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a>,<wbr/> and
-if if it less than <a href="#static_android.sensor.maxAnalogSensitivity">android.<wbr/>sensor.<wbr/>max<wbr/>Analog<wbr/>Sensitivity</a>,<wbr/> the camera device
-is guaranteed to use only analog amplification for applying the gain.<wbr/></p>
-<p>If the camera device cannot apply the exact sensitivity
-requested,<wbr/> it will reduce the gain to the nearest supported
-value.<wbr/> The final sensitivity used will be available in the
-output capture result.<wbr/></p>
-<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
-OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>ISO 12232:2006 REI method is acceptable.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.sensor.testPatternData">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A pixel <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> that supplies the test pattern
-when <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a> is SOLID_<wbr/>COLOR.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Each color channel is treated as an unsigned 32-bit integer.<wbr/>
-The camera device then uses the most significant X bits
-that correspond to how many bits are in its Bayer raw sensor
-output.<wbr/></p>
-<p>For example,<wbr/> a sensor with RAW10 Bayer output would use the
-10 most significant bits from each color channel.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.sensor.testPatternMode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No test pattern mode is used,<wbr/> and the camera
-device returns captures from the image sensor.<wbr/></p>
-<p>This is the default if the key is not set.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SOLID_COLOR</span>
-                    <span class="entry_type_enum_notes"><p>Each pixel in <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> is replaced by its
-respective color channel provided in
-<a href="#controls_android.sensor.testPatternData">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data</a>.<wbr/></p>
-<p>For example:</p>
-<pre><code>android.<wbr/>testPatternData = [0,<wbr/> 0xFFFFFFFF,<wbr/> 0xFFFFFFFF,<wbr/> 0]
-</code></pre>
-<p>All green pixels are 100% green.<wbr/> All red/<wbr/>blue pixels are black.<wbr/></p>
-<pre><code>android.<wbr/>testPatternData = [0xFFFFFFFF,<wbr/> 0,<wbr/> 0xFFFFFFFF,<wbr/> 0]
-</code></pre>
-<p>All red pixels are 100% red.<wbr/> Only the odd green pixels
-are 100% green.<wbr/> All blue pixels are 100% black.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">COLOR_BARS</span>
-                    <span class="entry_type_enum_notes"><p>All pixel data is replaced with an 8-bar color pattern.<wbr/></p>
-<p>The vertical bars (left-to-right) are as follows:</p>
-<ul>
-<li>100% white</li>
-<li>yellow</li>
-<li>cyan</li>
-<li>green</li>
-<li>magenta</li>
-<li>red</li>
-<li>blue</li>
-<li>black</li>
-</ul>
-<p>In general the image would look like the following:</p>
-<pre><code>W Y C G M R B K
-W Y C G M R B K
-W Y C G M R B K
-W Y C G M R B K
-W Y C G M R B K
-.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
-.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
-.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
-
-(B = Blue,<wbr/> K = Black)
-</code></pre>
-<p>Each bar should take up 1/<wbr/>8 of the sensor pixel array width.<wbr/>
-When this is not possible,<wbr/> the bar size should be rounded
-down to the nearest integer and the pattern can repeat
-on the right side.<wbr/></p>
-<p>Each bar's height must always take up the full sensor
-pixel array height.<wbr/></p>
-<p>Each pixel in this test pattern must be set to either
-0% intensity or 100% intensity.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">COLOR_BARS_FADE_TO_GRAY</span>
-                    <span class="entry_type_enum_notes"><p>The test pattern is similar to COLOR_<wbr/>BARS,<wbr/> except that
-each bar should start at its specified color at the top,<wbr/>
-and fade to gray at the bottom.<wbr/></p>
-<p>Furthermore each bar is further subdivided into a left and
-right half.<wbr/> The left half should have a smooth gradient,<wbr/>
-and the right half should have a quantized gradient.<wbr/></p>
-<p>In particular,<wbr/> the right half's should consist of blocks of the
-same color for 1/<wbr/>16th active sensor pixel array width.<wbr/></p>
-<p>The least significant bits in the quantized gradient should
-be copied from the most significant bits of the smooth gradient.<wbr/></p>
-<p>The height of each bar should always be a multiple of 128.<wbr/>
-When this is not the case,<wbr/> the pattern should repeat at the bottom
-of the image.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PN9</span>
-                    <span class="entry_type_enum_notes"><p>All pixel data is replaced by a pseudo-random sequence
-generated from a PN9 512-bit sequence (typically implemented
-in hardware with a linear feedback shift register).<wbr/></p>
-<p>The generator should be reset at the beginning of each frame,<wbr/>
-and thus each subsequent raw frame with this test pattern should
-be exactly the same as the last.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CUSTOM1</span>
-                    <span class="entry_type_enum_value">256</span>
-                    <span class="entry_type_enum_notes"><p>The first custom test pattern.<wbr/> All custom patterns that are
-available only on this camera device are at least this numeric
-value.<wbr/></p>
-<p>All of the custom test patterns will be static
-(that is the raw image must not vary from frame to frame).<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>When enabled,<wbr/> the sensor sends a test pattern instead of
-doing a real exposure from the camera.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.sensor.availableTestPatternModes">android.<wbr/>sensor.<wbr/>available<wbr/>Test<wbr/>Pattern<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When a test pattern is enabled,<wbr/> all manual sensor controls specified
-by android.<wbr/>sensor.<wbr/>* will be ignored.<wbr/> All other controls should
-work as normal.<wbr/></p>
-<p>For example,<wbr/> if manual flash is enabled,<wbr/> flash firing should still
-occur (and that the test pattern remain unmodified,<wbr/> since the flash
-would not actually affect it).<wbr/></p>
-<p>Defaults to OFF.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>All test patterns are specified in the Bayer domain.<wbr/></p>
-<p>The HAL may choose to substitute test patterns from the sensor
-with test patterns from on-device memory.<wbr/> In that case,<wbr/> it should be
-indistinguishable to the ISP whether the data came from the
-sensor interconnect bus (such as CSI2) or memory.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-                
-            
-
-                
-          <tr class="entry" id="static_android.sensor.info.activeArraySize">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public as rectangle]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">Four ints defining the active pixel rectangle</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The area of the image sensor which corresponds to active pixels after any geometric
-distortion correction has been applied.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixel coordinates on the image sensor
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is the rectangle representing the size of the active region of the sensor (i.<wbr/>e.<wbr/>
-the region that actually receives light from the scene) after any geometric correction
-has been applied,<wbr/> and should be treated as the maximum size in pixels of any of the
-image output formats aside from the raw formats.<wbr/></p>
-<p>This rectangle is defined relative to the full pixel array; (0,<wbr/>0) is the top-left of
-the full pixel array,<wbr/> and the size of the full pixel array is given by
-<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-<p>The coordinate system for most other keys that list pixel coordinates,<wbr/> including
-<a href="#controls_android.scaler.cropRegion">android.<wbr/>scaler.<wbr/>crop<wbr/>Region</a>,<wbr/> is defined relative to the active array rectangle given in
-this field,<wbr/> with <code>(0,<wbr/> 0)</code> being the top-left of this rectangle.<wbr/></p>
-<p>The active array may be smaller than the full pixel array,<wbr/> since the full array may
-include black calibration pixels or other inactive regions,<wbr/> and geometric correction
-resulting in scaling or cropping may have been applied.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This array contains <code>(xmin,<wbr/> ymin,<wbr/> width,<wbr/> height)</code>.<wbr/> The <code>(xmin,<wbr/> ymin)</code> must be
-&gt;= <code>(0,<wbr/>0)</code>.<wbr/>
-The <code>(width,<wbr/> height)</code> must be &lt;= <code><a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a></code>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.info.sensitivityRange">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as rangeInt]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">Range of supported sensitivities</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Range of sensitivities for <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> supported by this
-camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Min &lt;= 100,<wbr/> Max &gt;= 800</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The values are the standard ISO sensitivity values,<wbr/>
-as defined in ISO 12232:2006.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.info.colorFilterArrangement">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">RGGB</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">GRBG</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">GBRG</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">BGGR</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">RGB</span>
-                    <span class="entry_type_enum_notes"><p>Sensor is not Bayer; output has 3 16-bit
-values for each pixel,<wbr/> instead of just 1 16-bit value
-per pixel.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The arrangement of color filters on sensor;
-represents the colors in the top-left 2x2 section of
-the sensor,<wbr/> in reading order.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.info.exposureTimeRange">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as rangeLong]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">nanoseconds</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The range of image exposure times for <a href="#controls_android.sensor.exposureTime">android.<wbr/>sensor.<wbr/>exposure<wbr/>Time</a> supported
-by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p>The minimum exposure time will be less than 100 us.<wbr/> For FULL
-capability devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/>
-the maximum exposure time will be greater than 100ms.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For FULL capability devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/>
-The maximum of the range SHOULD be at least 1 second (1e9),<wbr/> MUST be at least
-100ms.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.info.maxFrameDuration">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum possible frame duration (minimum frame rate) for
-<a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> that is supported this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p>For FULL capability devices
-(<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/> at least 100ms.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Attempting to use frame durations beyond the maximum will result in the frame
-duration being clipped to the maximum.<wbr/> See that control for a full definition of frame
-durations.<wbr/></p>
-<p>Refer to <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>
-for the minimum frame duration values.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For FULL capability devices (<a href="#static_android.info.supportedHardwareLevel">android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level</a> == FULL),<wbr/>
-The maximum of the range SHOULD be at least
-1 second (1e9),<wbr/> MUST be at least 100ms (100e6).<wbr/></p>
-<p><a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a> must be greater or
-equal to the <a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a> max
-value (since exposure time overrides frame duration).<wbr/></p>
-<p>Available minimum frame durations for JPEG must be no greater
-than that of the YUV_<wbr/>420_<wbr/>888/<wbr/>IMPLEMENTATION_<wbr/>DEFINED
-minimum frame durations (for that respective size).<wbr/></p>
-<p>Since JPEG processing is considered offline and can take longer than
-a single uncompressed capture,<wbr/> refer to
-<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a>
-for details about encoding this scenario.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.info.physicalSize">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>physical<wbr/>Size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as sizeF]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">width x height</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The physical dimensions of the full pixel
-array.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Millimeters
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is the physical size of the sensor pixel
-array defined by <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Needed for FOV calculation for old API</p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.info.pixelArraySize">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [public as size]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Dimensions of the full pixel array,<wbr/> possibly
-including black calibration pixels.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixels
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The pixel count of the full pixel array of the image sensor,<wbr/> which covers
-<a href="#static_android.sensor.info.physicalSize">android.<wbr/>sensor.<wbr/>info.<wbr/>physical<wbr/>Size</a> area.<wbr/>  This represents the full pixel dimensions of
-the raw buffers produced by this sensor.<wbr/></p>
-<p>If a camera device supports raw sensor formats,<wbr/> either this or
-<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> is the maximum dimensions for the raw
-output formats listed in <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> (this depends on
-whether or not the image sensor returns buffers containing pixels that are not
-part of the active array region for blacklevel calibration or other purposes).<wbr/></p>
-<p>Some parts of the full pixel array may not receive light from the scene,<wbr/>
-or be otherwise inactive.<wbr/>  The <a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> key
-defines the rectangle of active pixels that will be included in processed image
-formats.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.info.whiteLevel">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Maximum raw value output by sensor.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt; 255 (8-bit output)</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This specifies the fully-saturated encoding level for the raw
-sample values from the sensor.<wbr/>  This is typically caused by the
-sensor becoming highly non-linear or clipping.<wbr/> The minimum for
-each channel is specified by the offset in the
-<a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> key.<wbr/></p>
-<p>The white level is typically determined either by sensor bit depth
-(8-14 bits is expected),<wbr/> or by the point where the sensor response
-becomes too non-linear to be useful.<wbr/>  The default value for this is
-maximum representable value for a 16-bit raw sample (2^16 - 1).<wbr/></p>
-<p>The white level values of captured images may vary for different
-capture settings (e.<wbr/>g.,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>).<wbr/> This key
-represents a coarse approximation for such case.<wbr/> It is recommended
-to use <a href="#dynamic_android.sensor.dynamicWhiteLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>White<wbr/>Level</a> for captures when supported
-by the camera device,<wbr/> which provides more accurate white level values.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The full bit depth of the sensor must be available in the raw data,<wbr/>
-so the value for linear sensors should not be significantly lower
-than maximum raw value supported,<wbr/> i.<wbr/>e.<wbr/> 2^(sensor bits per pixel).<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.info.timestampSource">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">UNKNOWN</span>
-                    <span class="entry_type_enum_notes"><p>Timestamps from <a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> are in nanoseconds and monotonic,<wbr/>
-but can not be compared to timestamps from other subsystems
-(e.<wbr/>g.<wbr/> accelerometer,<wbr/> gyro etc.<wbr/>),<wbr/> or other instances of the same or different
-camera devices in the same system.<wbr/> Timestamps between streams and results for
-a single camera instance are comparable,<wbr/> and the timestamps for all buffers
-and the result metadata generated by a single capture are identical.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">REALTIME</span>
-                    <span class="entry_type_enum_notes"><p>Timestamps from <a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> are in the same timebase as
-<a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">SystemClock#elapsedRealtimeNanos</a>,<wbr/>
-and they can be compared to other timestamps using that base.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The time base source for sensor capture start timestamps.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The timestamps provided for captures are always in nanoseconds and monotonic,<wbr/> but
-may not based on a time source that can be compared to other system time sources.<wbr/></p>
-<p>This characteristic defines the source for the timestamps,<wbr/> and therefore whether they
-can be compared against other system time sources/<wbr/>timestamps.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For camera devices implement UNKNOWN,<wbr/> the camera framework expects that the timestamp
-source to be SYSTEM_<wbr/>TIME_<wbr/>MONOTONIC.<wbr/> For camera devices implement REALTIME,<wbr/> the camera
-framework expects that the timestamp source to be SYSTEM_<wbr/>TIME_<wbr/>BOOTTIME.<wbr/> See
-system/<wbr/>core/<wbr/>include/<wbr/>utils/<wbr/>Timers.<wbr/>h for the definition of SYSTEM_<wbr/>TIME_<wbr/>MONOTONIC and
-SYSTEM_<wbr/>TIME_<wbr/>BOOTTIME.<wbr/> Note that HAL must follow above expectation; otherwise video
-recording might suffer unexpected behavior.<wbr/></p>
-<p>Also,<wbr/> camera devices implements REALTIME must pass the ITS sensor fusion test which
-tests the alignment between camera timestamps and gyro sensor timestamps.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.info.lensShadingApplied">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">FALSE</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">TRUE</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether the RAW images output from this camera device are subject to
-lens shading correction.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If TRUE,<wbr/> all images produced by the camera device in the RAW image formats will
-have lens shading correction already applied to it.<wbr/> If FALSE,<wbr/> the images will
-not be adjusted for lens shading correction.<wbr/>
-See <a href="#static_android.request.maxNumOutputRaw">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Raw</a> for a list of RAW image formats.<wbr/></p>
-<p>This key will be <code>null</code> for all devices do not report this information.<wbr/>
-Devices with RAW capability will always report this information in this key.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.info.preCorrectionActiveArraySize">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public as rectangle]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">Four ints defining the active pixel rectangle</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The area of the image sensor which corresponds to active pixels prior to the
-application of any geometric distortion correction.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Pixel coordinates on the image sensor
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is the rectangle representing the size of the active region of the sensor (i.<wbr/>e.<wbr/>
-the region that actually receives light from the scene) before any geometric correction
-has been applied,<wbr/> and should be treated as the active region rectangle for any of the
-raw formats.<wbr/>  All metadata associated with raw processing (e.<wbr/>g.<wbr/> the lens shading
-correction map,<wbr/> and radial distortion fields) treats the top,<wbr/> left of this rectangle as
-the origin,<wbr/> (0,<wbr/>0).<wbr/></p>
-<p>The size of this region determines the maximum field of view and the maximum number of
-pixels that an image from this sensor can contain,<wbr/> prior to the application of
-geometric distortion correction.<wbr/> The effective maximum pixel dimensions of a
-post-distortion-corrected image is given by the <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>
-field,<wbr/> and the effective maximum field of view for a post-distortion-corrected image
-can be calculated by applying the geometric distortion correction fields to this
-rectangle,<wbr/> and cropping to the rectangle given in <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-<p>E.<wbr/>g.<wbr/> to calculate position of a pixel,<wbr/> (x,<wbr/>y),<wbr/> in a processed YUV output image with the
-dimensions in <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> given the position of a pixel,<wbr/>
-(x',<wbr/> y'),<wbr/> in the raw pixel array with dimensions give in
-<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>:</p>
-<ol>
-<li>Choose a pixel (x',<wbr/> y') within the active array region of the raw buffer given in
-<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>,<wbr/> otherwise this pixel is considered
-to be outside of the FOV,<wbr/> and will not be shown in the processed output image.<wbr/></li>
-<li>Apply geometric distortion correction to get the post-distortion pixel coordinate,<wbr/>
-(x_<wbr/>i,<wbr/> y_<wbr/>i).<wbr/> When applying geometric correction metadata,<wbr/> note that metadata for raw
-buffers is defined relative to the top,<wbr/> left of the
-<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> rectangle.<wbr/></li>
-<li>If the resulting corrected pixel coordinate is within the region given in
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> then the position of this pixel in the
-processed output image buffer is <code>(x_<wbr/>i - activeArray.<wbr/>left,<wbr/> y_<wbr/>i - activeArray.<wbr/>top)</code>,<wbr/>
-when the top,<wbr/> left coordinate of that buffer is treated as (0,<wbr/> 0).<wbr/></li>
-</ol>
-<p>Thus,<wbr/> for pixel x',<wbr/>y' = (25,<wbr/> 25) on a sensor where <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>
-is (100,<wbr/>100),<wbr/> <a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a> is (10,<wbr/> 10,<wbr/> 100,<wbr/> 100),<wbr/>
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a> is (20,<wbr/> 20,<wbr/> 80,<wbr/> 80),<wbr/> and the geometric distortion
-correction doesn't change the pixel coordinate,<wbr/> the resulting pixel selected in
-pixel coordinates would be x,<wbr/>y = (25,<wbr/> 25) relative to the top,<wbr/>left of the raw buffer
-with dimensions given in <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>,<wbr/> and would be (5,<wbr/> 5)
-relative to the top,<wbr/>left of post-processed YUV output buffer with dimensions given in
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-<p>The currently supported fields that correct for geometric distortion are:</p>
-<ol>
-<li><a href="#static_android.lens.radialDistortion">android.<wbr/>lens.<wbr/>radial<wbr/>Distortion</a>.<wbr/></li>
-</ol>
-<p>If all of the geometric distortion fields are no-ops,<wbr/> this rectangle will be the same
-as the post-distortion-corrected rectangle given in
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-<p>This rectangle is defined relative to the full pixel array; (0,<wbr/>0) is the top-left of
-the full pixel array,<wbr/> and the size of the full pixel array is given by
-<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-<p>The pre-correction active array may be smaller than the full pixel array,<wbr/> since the
-full array may include black calibration pixels or other inactive regions.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This array contains <code>(xmin,<wbr/> ymin,<wbr/> width,<wbr/> height)</code>.<wbr/> The <code>(xmin,<wbr/> ymin)</code> must be
-&gt;= <code>(0,<wbr/>0)</code>.<wbr/>
-The <code>(width,<wbr/> height)</code> must be &lt;= <code><a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a></code>.<wbr/></p>
-<p>If omitted by the HAL implementation,<wbr/> the camera framework will assume that this is
-the same as the post-correction active array region given in
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-        
-
-                
-          <tr class="entry" id="static_android.sensor.referenceIlluminant1">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">DAYLIGHT</span>
-                    <span class="entry_type_enum_value">1</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FLUORESCENT</span>
-                    <span class="entry_type_enum_value">2</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">TUNGSTEN</span>
-                    <span class="entry_type_enum_value">3</span>
-                    <span class="entry_type_enum_notes"><p>Incandescent light</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FLASH</span>
-                    <span class="entry_type_enum_value">4</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FINE_WEATHER</span>
-                    <span class="entry_type_enum_value">9</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CLOUDY_WEATHER</span>
-                    <span class="entry_type_enum_value">10</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SHADE</span>
-                    <span class="entry_type_enum_value">11</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">DAYLIGHT_FLUORESCENT</span>
-                    <span class="entry_type_enum_value">12</span>
-                    <span class="entry_type_enum_notes"><p>D 5700 - 7100K</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">DAY_WHITE_FLUORESCENT</span>
-                    <span class="entry_type_enum_value">13</span>
-                    <span class="entry_type_enum_notes"><p>N 4600 - 5400K</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">COOL_WHITE_FLUORESCENT</span>
-                    <span class="entry_type_enum_value">14</span>
-                    <span class="entry_type_enum_notes"><p>W 3900 - 4500K</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">WHITE_FLUORESCENT</span>
-                    <span class="entry_type_enum_value">15</span>
-                    <span class="entry_type_enum_notes"><p>WW 3200 - 3700K</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">STANDARD_A</span>
-                    <span class="entry_type_enum_value">17</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">STANDARD_B</span>
-                    <span class="entry_type_enum_value">18</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">STANDARD_C</span>
-                    <span class="entry_type_enum_value">19</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">D55</span>
-                    <span class="entry_type_enum_value">20</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">D65</span>
-                    <span class="entry_type_enum_value">21</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">D75</span>
-                    <span class="entry_type_enum_value">22</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">D50</span>
-                    <span class="entry_type_enum_value">23</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ISO_STUDIO_TUNGSTEN</span>
-                    <span class="entry_type_enum_value">24</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The standard reference illuminant used as the scene light source when
-calculating the <a href="#static_android.sensor.colorTransform1">android.<wbr/>sensor.<wbr/>color<wbr/>Transform1</a>,<wbr/>
-<a href="#static_android.sensor.calibrationTransform1">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform1</a>,<wbr/> and
-<a href="#static_android.sensor.forwardMatrix1">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix1</a> matrices.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The values in this key correspond to the values defined for the
-EXIF LightSource tag.<wbr/> These illuminants are standard light sources
-that are often used calibrating camera devices.<wbr/></p>
-<p>If this key is present,<wbr/> then <a href="#static_android.sensor.colorTransform1">android.<wbr/>sensor.<wbr/>color<wbr/>Transform1</a>,<wbr/>
-<a href="#static_android.sensor.calibrationTransform1">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform1</a>,<wbr/> and
-<a href="#static_android.sensor.forwardMatrix1">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix1</a> will also be present.<wbr/></p>
-<p>Some devices may choose to provide a second set of calibration
-information for improved quality,<wbr/> including
-<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a> and its corresponding matrices.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The first reference illuminant (<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>)
-and corresponding matrices must be present to support the RAW capability
-and DNG output.<wbr/></p>
-<p>When producing raw images with a color profile that has only been
-calibrated against a single light source,<wbr/> it is valid to omit
-<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a> along with the
-<a href="#static_android.sensor.colorTransform2">android.<wbr/>sensor.<wbr/>color<wbr/>Transform2</a>,<wbr/> <a href="#static_android.sensor.calibrationTransform2">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2</a>,<wbr/>
-and <a href="#static_android.sensor.forwardMatrix2">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2</a> matrices.<wbr/></p>
-<p>If only <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a> is included,<wbr/> it should be
-chosen so that it is representative of typical scene lighting.<wbr/>  In
-general,<wbr/> D50 or DAYLIGHT will be chosen for this case.<wbr/></p>
-<p>If both <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a> and
-<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a> are included,<wbr/> they should be
-chosen to represent the typical range of scene lighting conditions.<wbr/>
-In general,<wbr/> low color temperature illuminant such as Standard-A will
-be chosen for the first reference illuminant and a higher color
-temperature illuminant such as D65 will be chosen for the second
-reference illuminant.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.referenceIlluminant2">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The standard reference illuminant used as the scene light source when
-calculating the <a href="#static_android.sensor.colorTransform2">android.<wbr/>sensor.<wbr/>color<wbr/>Transform2</a>,<wbr/>
-<a href="#static_android.sensor.calibrationTransform2">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2</a>,<wbr/> and
-<a href="#static_android.sensor.forwardMatrix2">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2</a> matrices.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>See <a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a> for more details.<wbr/></p>
-<p>If this key is present,<wbr/> then <a href="#static_android.sensor.colorTransform2">android.<wbr/>sensor.<wbr/>color<wbr/>Transform2</a>,<wbr/>
-<a href="#static_android.sensor.calibrationTransform2">android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2</a>,<wbr/> and
-<a href="#static_android.sensor.forwardMatrix2">android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2</a> will also be present.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.calibrationTransform1">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform1
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3 x 3
-                </span>
-              <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
-
-
-
-
-                <div class="entry_type_notes">3x3 matrix in row-major-order</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A per-device calibration transform matrix that maps from the
-reference sensor colorspace to the actual device sensor colorspace.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This matrix is used to correct for per-device variations in the
-sensor colorspace,<wbr/> and is used for processing raw buffer data.<wbr/></p>
-<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and
-contains a per-device calibration transform that maps colors
-from reference sensor color space (i.<wbr/>e.<wbr/> the "golden module"
-colorspace) into this camera device's native sensor color
-space under the first reference illuminant
-(<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.calibrationTransform2">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>calibration<wbr/>Transform2
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3 x 3
-                </span>
-              <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
-
-
-
-
-                <div class="entry_type_notes">3x3 matrix in row-major-order</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A per-device calibration transform matrix that maps from the
-reference sensor colorspace to the actual device sensor colorspace
-(this is the colorspace of the raw buffer data).<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This matrix is used to correct for per-device variations in the
-sensor colorspace,<wbr/> and is used for processing raw buffer data.<wbr/></p>
-<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and
-contains a per-device calibration transform that maps colors
-from reference sensor color space (i.<wbr/>e.<wbr/> the "golden module"
-colorspace) into this camera device's native sensor color
-space under the second reference illuminant
-(<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a>).<wbr/></p>
-<p>This matrix will only be present if the second reference
-illuminant is present.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.colorTransform1">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>color<wbr/>Transform1
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3 x 3
-                </span>
-              <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
-
-
-
-
-                <div class="entry_type_notes">3x3 matrix in row-major-order</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A matrix that transforms color values from CIE XYZ color space to
-reference sensor color space.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This matrix is used to convert from the standard CIE XYZ color
-space to the reference sensor colorspace,<wbr/> and is used when processing
-raw buffer data.<wbr/></p>
-<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and
-contains a color transform matrix that maps colors from the CIE
-XYZ color space to the reference sensor color space (i.<wbr/>e.<wbr/> the
-"golden module" colorspace) under the first reference illuminant
-(<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>).<wbr/></p>
-<p>The white points chosen in both the reference sensor color space
-and the CIE XYZ colorspace when calculating this transform will
-match the standard white point for the first reference illuminant
-(i.<wbr/>e.<wbr/> no chromatic adaptation will be applied by this transform).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.colorTransform2">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>color<wbr/>Transform2
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3 x 3
-                </span>
-              <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
-
-
-
-
-                <div class="entry_type_notes">3x3 matrix in row-major-order</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A matrix that transforms color values from CIE XYZ color space to
-reference sensor color space.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This matrix is used to convert from the standard CIE XYZ color
-space to the reference sensor colorspace,<wbr/> and is used when processing
-raw buffer data.<wbr/></p>
-<p>The matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and
-contains a color transform matrix that maps colors from the CIE
-XYZ color space to the reference sensor color space (i.<wbr/>e.<wbr/> the
-"golden module" colorspace) under the second reference illuminant
-(<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a>).<wbr/></p>
-<p>The white points chosen in both the reference sensor color space
-and the CIE XYZ colorspace when calculating this transform will
-match the standard white point for the second reference illuminant
-(i.<wbr/>e.<wbr/> no chromatic adaptation will be applied by this transform).<wbr/></p>
-<p>This matrix will only be present if the second reference
-illuminant is present.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.forwardMatrix1">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix1
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3 x 3
-                </span>
-              <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
-
-
-
-
-                <div class="entry_type_notes">3x3 matrix in row-major-order</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A matrix that transforms white balanced camera colors from the reference
-sensor colorspace to the CIE XYZ colorspace with a D50 whitepoint.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This matrix is used to convert to the standard CIE XYZ colorspace,<wbr/> and
-is used when processing raw buffer data.<wbr/></p>
-<p>This matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and contains
-a color transform matrix that maps white balanced colors from the
-reference sensor color space to the CIE XYZ color space with a D50 white
-point.<wbr/></p>
-<p>Under the first reference illuminant (<a href="#static_android.sensor.referenceIlluminant1">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant1</a>)
-this matrix is chosen so that the standard white point for this reference
-illuminant in the reference sensor colorspace is mapped to D50 in the
-CIE XYZ colorspace.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.forwardMatrix2">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>forward<wbr/>Matrix2
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3 x 3
-                </span>
-              <span class="entry_type_visibility"> [public as colorSpaceTransform]</span>
-
-
-
-
-                <div class="entry_type_notes">3x3 matrix in row-major-order</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A matrix that transforms white balanced camera colors from the reference
-sensor colorspace to the CIE XYZ colorspace with a D50 whitepoint.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This matrix is used to convert to the standard CIE XYZ colorspace,<wbr/> and
-is used when processing raw buffer data.<wbr/></p>
-<p>This matrix is expressed as a 3x3 matrix in row-major-order,<wbr/> and contains
-a color transform matrix that maps white balanced colors from the
-reference sensor color space to the CIE XYZ color space with a D50 white
-point.<wbr/></p>
-<p>Under the second reference illuminant (<a href="#static_android.sensor.referenceIlluminant2">android.<wbr/>sensor.<wbr/>reference<wbr/>Illuminant2</a>)
-this matrix is chosen so that the standard white point for this reference
-illuminant in the reference sensor colorspace is mapped to D50 in the
-CIE XYZ colorspace.<wbr/></p>
-<p>This matrix will only be present if the second reference
-illuminant is present.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.baseGainFactor">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>sensor.<wbr/>base<wbr/>Gain<wbr/>Factor
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Gain factor from electrons to raw units when
-ISO=100</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.blackLevelPattern">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public as blackLevelPattern]</span>
-
-
-
-
-                <div class="entry_type_notes">2x2 raw count block</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A fixed black level offset for each of the color filter arrangement
-(CFA) mosaic channels.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0 for each.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This key specifies the zero light value for each of the CFA mosaic
-channels in the camera sensor.<wbr/>  The maximal value output by the
-sensor is represented by the value in <a href="#static_android.sensor.info.whiteLevel">android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level</a>.<wbr/></p>
-<p>The values are given in the same order as channels listed for the CFA
-layout key (see <a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>),<wbr/> i.<wbr/>e.<wbr/> the
-nth value given corresponds to the black level offset for the nth
-color channel listed in the CFA.<wbr/></p>
-<p>The black level values of captured images may vary for different
-capture settings (e.<wbr/>g.,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>).<wbr/> This key
-represents a coarse approximation for such case.<wbr/> It is recommended to
-use <a href="#dynamic_android.sensor.dynamicBlackLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>Black<wbr/>Level</a> or use pixels from
-<a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> directly for captures when
-supported by the camera device,<wbr/> which provides more accurate black
-level values.<wbr/> For raw capture in particular,<wbr/> it is recommended to use
-pixels from <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> to calculate black
-level values for each frame.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The values are given in row-column scan order,<wbr/> with the first value
-corresponding to the element of the CFA in row=0,<wbr/> column=0.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.maxAnalogSensitivity">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>max<wbr/>Analog<wbr/>Sensitivity
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Maximum sensitivity that is implemented
-purely through analog gain.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_FULL">FULL</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a> values less than or
-equal to this,<wbr/> all applied gain must be analog.<wbr/> For
-values above this,<wbr/> the gain applied can be a mix of analog and
-digital.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.orientation">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>orientation
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Clockwise angle through which the output image needs to be rotated to be
-upright on the device screen in its native orientation.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Degrees of clockwise rotation; always a multiple of
-          90
-            </td>
-
-            <td class="entry_range">
-              <p>0,<wbr/> 90,<wbr/> 180,<wbr/> 270</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Also defines the direction of rolling shutter readout,<wbr/> which is from top to bottom in
-the sensor's coordinate system.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.profileHueSatMapDimensions">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map<wbr/>Dimensions
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-                <div class="entry_type_notes">Number of samples for hue,<wbr/> saturation,<wbr/> and value</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The number of input samples for each dimension of
-<a href="#dynamic_android.sensor.profileHueSatMap">android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map</a>.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Hue &gt;= 1,<wbr/>
-Saturation &gt;= 2,<wbr/>
-Value &gt;= 1</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The number of input samples for the hue,<wbr/> saturation,<wbr/> and value
-dimension of <a href="#dynamic_android.sensor.profileHueSatMap">android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map</a>.<wbr/> The order of the
-dimensions given is hue,<wbr/> saturation,<wbr/> value; where hue is the 0th
-element.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.availableTestPatternModes">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>available<wbr/>Test<wbr/>Pattern<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of sensor test pattern modes for <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a>
-supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Defaults to OFF,<wbr/> and always includes OFF if defined.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>All custom modes must be &gt;= CUSTOM1.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.opticalBlackRegions">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4 x num_regions
-                </span>
-              <span class="entry_type_visibility"> [public as rectangle]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of disjoint rectangles indicating the sensor
-optically shielded black pixel regions.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>In most camera sensors,<wbr/> the active array is surrounded by some
-optically shielded pixel areas.<wbr/> By blocking light,<wbr/> these pixels
-provides a reliable black reference for black level compensation
-in active array region.<wbr/></p>
-<p>This key provides a list of disjoint rectangles specifying the
-regions of optically shielded (with metal shield) black pixel
-regions if the camera device is capable of reading out these black
-pixels in the output raw images.<wbr/> In comparison to the fixed black
-level values reported by <a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a>,<wbr/> this key
-may provide a more accurate way for the application to calculate
-black level of each captured raw images.<wbr/></p>
-<p>When this key is reported,<wbr/> the <a href="#dynamic_android.sensor.dynamicBlackLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>Black<wbr/>Level</a> and
-<a href="#dynamic_android.sensor.dynamicWhiteLevel">android.<wbr/>sensor.<wbr/>dynamic<wbr/>White<wbr/>Level</a> will also be reported.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This array contains (xmin,<wbr/> ymin,<wbr/> width,<wbr/> height).<wbr/> The (xmin,<wbr/> ymin)
-must be &gt;= (0,<wbr/>0) and &lt;=
-<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/> The (width,<wbr/> height) must be
-&lt;= <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/> Each region must be
-outside the region reported by
-<a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pre<wbr/>Correction<wbr/>Active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-<p>The HAL must report minimal number of disjoint regions for the
-optically shielded back pixel regions.<wbr/> For example,<wbr/> if a region can
-be covered by one rectangle,<wbr/> the HAL must not split this region into
-multiple rectangles.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.sensor.opaqueRawSize">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>opaque<wbr/>Raw<wbr/>Size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 3
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Size in bytes for all the listed opaque RAW buffer sizes</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Must be large enough to fit the opaque RAW of corresponding size produced by
-the camera</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This configurations are listed as <code>(width,<wbr/> height,<wbr/> size_<wbr/>in_<wbr/>bytes)</code> tuples.<wbr/>
-This is used for sizing the gralloc buffers for opaque RAW buffers.<wbr/>
-All RAW_<wbr/>OPAQUE output stream configuration listed in
-<a href="#static_android.scaler.availableStreamConfigurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stream<wbr/>Configurations</a> will have a corresponding tuple in
-this key.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This key is added in HAL3.<wbr/>4.<wbr/>
-For HAL3.<wbr/>4 or above: devices advertising RAW_<wbr/>OPAQUE format output must list this key.<wbr/>
-For HAL3.<wbr/>3 or earlier devices: if RAW_<wbr/>OPAQUE ouput is advertised,<wbr/> camera framework
-will derive this key by assuming each pixel takes two bytes and no padding bytes
-between rows.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.sensor.exposureTime">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>exposure<wbr/>Time
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Duration each pixel is exposed to
-light.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If the sensor can't expose this exact duration,<wbr/> it will shorten the
-duration exposed to the nearest possible value (rather than expose longer).<wbr/>
-The final exposure time used will be available in the output capture result.<wbr/></p>
-<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
-OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.frameDuration">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>frame<wbr/>Duration
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Duration from start of frame exposure to
-start of next frame exposure.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p>See <a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a>,<wbr/>
-<a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a>.<wbr/> The duration
-is capped to <code>max(duration,<wbr/> exposureTime + overhead)</code>.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The maximum frame rate that can be supported by a camera subsystem is
-a function of many factors:</p>
-<ul>
-<li>Requested resolutions of output image streams</li>
-<li>Availability of binning /<wbr/> skipping modes on the imager</li>
-<li>The bandwidth of the imager interface</li>
-<li>The bandwidth of the various ISP processing blocks</li>
-</ul>
-<p>Since these factors can vary greatly between different ISPs and
-sensors,<wbr/> the camera abstraction tries to represent the bandwidth
-restrictions with as simple a model as possible.<wbr/></p>
-<p>The model presented has the following characteristics:</p>
-<ul>
-<li>The image sensor is always configured to output the smallest
-resolution possible given the application's requested output stream
-sizes.<wbr/>  The smallest resolution is defined as being at least as large
-as the largest requested output stream size; the camera pipeline must
-never digitally upsample sensor data when the crop region covers the
-whole sensor.<wbr/> In general,<wbr/> this means that if only small output stream
-resolutions are configured,<wbr/> the sensor can provide a higher frame
-rate.<wbr/></li>
-<li>Since any request may use any or all the currently configured
-output streams,<wbr/> the sensor and ISP must be configured to support
-scaling a single capture to all the streams at the same time.<wbr/>  This
-means the camera pipeline must be ready to produce the largest
-requested output size without any delay.<wbr/>  Therefore,<wbr/> the overall
-frame rate of a given configured stream set is governed only by the
-largest requested stream resolution.<wbr/></li>
-<li>Using more than one output stream in a request does not affect the
-frame duration.<wbr/></li>
-<li>Certain format-streams may need to do additional background processing
-before data is consumed/<wbr/>produced by that stream.<wbr/> These processors
-can run concurrently to the rest of the camera pipeline,<wbr/> but
-cannot process more than 1 capture at a time.<wbr/></li>
-</ul>
-<p>The necessary information for the application,<wbr/> given the model above,<wbr/>
-is provided via the <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> field using
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>.<wbr/>
-These are used to determine the maximum frame rate /<wbr/> minimum frame
-duration that is possible for a given stream configuration.<wbr/></p>
-<p>Specifically,<wbr/> the application can use the following rules to
-determine the minimum frame duration it can request from the camera
-device:</p>
-<ol>
-<li>Let the set of currently configured input/<wbr/>output streams
-be called <code>S</code>.<wbr/></li>
-<li>Find the minimum frame durations for each stream in <code>S</code>,<wbr/> by looking
-it up in <a href="#static_android.scaler.streamConfigurationMap">android.<wbr/>scaler.<wbr/>stream<wbr/>Configuration<wbr/>Map</a> using <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>
-(with its respective size/<wbr/>format).<wbr/> Let this set of frame durations be
-called <code>F</code>.<wbr/></li>
-<li>For any given request <code>R</code>,<wbr/> the minimum frame duration allowed
-for <code>R</code> is the maximum out of all values in <code>F</code>.<wbr/> Let the streams
-used in <code>R</code> be called <code>S_<wbr/>r</code>.<wbr/></li>
-</ol>
-<p>If none of the streams in <code>S_<wbr/>r</code> have a stall time (listed in <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>
-using its respective size/<wbr/>format),<wbr/> then the frame duration in <code>F</code>
-determines the steady state frame rate that the application will get
-if it uses <code>R</code> as a repeating request.<wbr/> Let this special kind of
-request be called <code>Rsimple</code>.<wbr/></p>
-<p>A repeating request <code>Rsimple</code> can be <em>occasionally</em> interleaved
-by a single capture of a new request <code>Rstall</code> (which has at least
-one in-use stream with a non-0 stall time) and if <code>Rstall</code> has the
-same minimum frame duration this will not cause a frame rate loss
-if all buffers from the previous <code>Rstall</code> have already been
-delivered.<wbr/></p>
-<p>For more details about stalling,<wbr/> see
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputStallDuration">StreamConfigurationMap#getOutputStallDuration</a>.<wbr/></p>
-<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
-OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For more details about stalling,<wbr/> see
-<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.sensitivity">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>sensitivity
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The amount of gain applied to sensor data
-before processing.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              ISO arithmetic units
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The sensitivity is the standard ISO sensitivity value,<wbr/>
-as defined in ISO 12232:2006.<wbr/></p>
-<p>The sensitivity must be within <a href="#static_android.sensor.info.sensitivityRange">android.<wbr/>sensor.<wbr/>info.<wbr/>sensitivity<wbr/>Range</a>,<wbr/> and
-if if it less than <a href="#static_android.sensor.maxAnalogSensitivity">android.<wbr/>sensor.<wbr/>max<wbr/>Analog<wbr/>Sensitivity</a>,<wbr/> the camera device
-is guaranteed to use only analog amplification for applying the gain.<wbr/></p>
-<p>If the camera device cannot apply the exact sensitivity
-requested,<wbr/> it will reduce the gain to the nearest supported
-value.<wbr/> The final sensitivity used will be available in the
-output capture result.<wbr/></p>
-<p>This control is only effective if <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> or <a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> is set to
-OFF; otherwise the auto-exposure algorithm will override this value.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>ISO 12232:2006 REI method is acceptable.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.timestamp">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>timestamp
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Time at start of exposure of first
-row of the image sensor active array,<wbr/> in nanoseconds.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p>&gt; 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The timestamps are also included in all image
-buffers produced for the same capture,<wbr/> and will be identical
-on all the outputs.<wbr/></p>
-<p>When <a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> UNKNOWN,<wbr/>
-the timestamps measure time since an unspecified starting point,<wbr/>
-and are monotonically increasing.<wbr/> They can be compared with the
-timestamps for other captures from the same camera device,<wbr/> but are
-not guaranteed to be comparable to any other time source.<wbr/></p>
-<p>When <a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> REALTIME,<wbr/> the
-timestamps measure time in the same timebase as <a href="https://developer.android.com/reference/android/os/SystemClock.html#elapsedRealtimeNanos">SystemClock#elapsedRealtimeNanos</a>,<wbr/> and they can
-be compared to other timestamps from other subsystems that
-are using that base.<wbr/></p>
-<p>For reprocessing,<wbr/> the timestamp will match the start of exposure of
-the input image,<wbr/> i.<wbr/>e.<wbr/> <a href="https://developer.android.com/reference/CaptureResult.html#SENSOR_TIMESTAMP">the
-timestamp</a> in the TotalCaptureResult that was used to create the
-reprocess capture request.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>All timestamps must be in reference to the kernel's
-CLOCK_<wbr/>BOOTTIME monotonic clock,<wbr/> which properly accounts for
-time spent asleep.<wbr/> This allows for synchronization with
-sensors that continue to operate while the system is
-otherwise asleep.<wbr/></p>
-<p>If <a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> REALTIME,<wbr/>
-The timestamp must be synchronized with the timestamps from other
-sensor subsystems that are using the same timebase.<wbr/></p>
-<p>For reprocessing,<wbr/> the input image's start of exposure can be looked up
-with <a href="#dynamic_android.sensor.timestamp">android.<wbr/>sensor.<wbr/>timestamp</a> from the metadata included in the
-capture request.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.temperature">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>sensor.<wbr/>temperature
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The temperature of the sensor,<wbr/> sampled at the time
-exposure began for this frame.<wbr/></p>
-<p>The thermal diode being queried should be inside the sensor PCB,<wbr/> or
-somewhere close to it.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Celsius
-            </td>
-
-            <td class="entry_range">
-              <p>Optional.<wbr/> This value is missing if no temperature is available.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.neutralColorPoint">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>neutral<wbr/>Color<wbr/>Point
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The estimated camera neutral color in the native sensor colorspace at
-the time of capture.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This value gives the neutral color point encoded as an RGB value in the
-native sensor color space.<wbr/>  The neutral color point indicates the
-currently estimated white point of the scene illumination.<wbr/>  It can be
-used to interpolate between the provided color transforms when
-processing raw sensor data.<wbr/></p>
-<p>The order of the values is R,<wbr/> G,<wbr/> B; where R is in the lowest index.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.noiseProfile">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>noise<wbr/>Profile
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">double</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2 x CFA Channels
-                </span>
-              <span class="entry_type_visibility"> [public as pairDoubleDouble]</span>
-
-
-
-
-                <div class="entry_type_notes">Pairs of noise model coefficients</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Noise model coefficients for each CFA mosaic channel.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This key contains two noise model coefficients for each CFA channel
-corresponding to the sensor amplification (S) and sensor readout
-noise (O).<wbr/>  These are given as pairs of coefficients for each channel
-in the same order as channels listed for the CFA layout key
-(see <a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>).<wbr/>  This is
-represented as an array of Pair&lt;Double,<wbr/> Double&gt;,<wbr/> where
-the first member of the Pair at index n is the S coefficient and the
-second member is the O coefficient for the nth color channel in the CFA.<wbr/></p>
-<p>These coefficients are used in a two parameter noise model to describe
-the amount of noise present in the image for each CFA channel.<wbr/>  The
-noise model used here is:</p>
-<p>N(x) = sqrt(Sx + O)</p>
-<p>Where x represents the recorded signal of a CFA channel normalized to
-the range [0,<wbr/> 1],<wbr/> and S and O are the noise model coeffiecients for
-that channel.<wbr/></p>
-<p>A more detailed description of the noise model can be found in the
-Adobe DNG specification for the NoiseProfile tag.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For a CFA layout of RGGB,<wbr/> the list of coefficients would be given as
-an array of doubles S0,<wbr/>O0,<wbr/>S1,<wbr/>O1,...,<wbr/> where S0 and O0 are the coefficients
-for the red channel,<wbr/> S1 and O1 are the coefficients for the first green
-channel,<wbr/> etc.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.profileHueSatMap">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  hue_samples x saturation_samples x value_samples x 3
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-                <div class="entry_type_notes">Mapping for hue,<wbr/> saturation,<wbr/> and value</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A mapping containing a hue shift,<wbr/> saturation scale,<wbr/> and value scale
-for each pixel.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              
-          The hue shift is given in degrees; saturation and value scale factors are
-          unitless and are between 0 and 1 inclusive
-          
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>hue_<wbr/>samples,<wbr/> saturation_<wbr/>samples,<wbr/> and value_<wbr/>samples are given in
-<a href="#static_android.sensor.profileHueSatMapDimensions">android.<wbr/>sensor.<wbr/>profile<wbr/>Hue<wbr/>Sat<wbr/>Map<wbr/>Dimensions</a>.<wbr/></p>
-<p>Each entry of this map contains three floats corresponding to the
-hue shift,<wbr/> saturation scale,<wbr/> and value scale,<wbr/> respectively; where the
-hue shift has the lowest index.<wbr/> The map entries are stored in the key
-in nested loop order,<wbr/> with the value divisions in the outer loop,<wbr/> the
-hue divisions in the middle loop,<wbr/> and the saturation divisions in the
-inner loop.<wbr/> All zero input saturation entries are required to have a
-value scale factor of 1.<wbr/>0.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.profileToneCurve">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>sensor.<wbr/>profile<wbr/>Tone<wbr/>Curve
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  samples x 2
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-                <div class="entry_type_notes">Samples defining a spline for a tone-mapping curve</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A list of x,<wbr/>y samples defining a tone-mapping curve for gamma adjustment.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Each sample has an input range of <code>[0,<wbr/> 1]</code> and an output range of
-<code>[0,<wbr/> 1]</code>.<wbr/>  The first sample is required to be <code>(0,<wbr/> 0)</code>,<wbr/> and the last
-sample is required to be <code>(1,<wbr/> 1)</code>.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This key contains a default tone curve that can be applied while
-processing the image as a starting point for user adjustments.<wbr/>
-The curve is specified as a list of value pairs in linear gamma.<wbr/>
-The curve is interpolated using a cubic spline.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.greenSplit">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>green<wbr/>Split
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The worst-case divergence between Bayer green channels.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This value is an estimate of the worst case split between the
-Bayer green channels in the red and blue rows in the sensor color
-filter array.<wbr/></p>
-<p>The green split is calculated as follows:</p>
-<ol>
-<li>A 5x5 pixel (or larger) window W within the active sensor array is
-chosen.<wbr/> The term 'pixel' here is taken to mean a group of 4 Bayer
-mosaic channels (R,<wbr/> Gr,<wbr/> Gb,<wbr/> B).<wbr/>  The location and size of the window
-chosen is implementation defined,<wbr/> and should be chosen to provide a
-green split estimate that is both representative of the entire image
-for this camera sensor,<wbr/> and can be calculated quickly.<wbr/></li>
-<li>The arithmetic mean of the green channels from the red
-rows (mean_<wbr/>Gr) within W is computed.<wbr/></li>
-<li>The arithmetic mean of the green channels from the blue
-rows (mean_<wbr/>Gb) within W is computed.<wbr/></li>
-<li>The maximum ratio R of the two means is computed as follows:
-<code>R = max((mean_<wbr/>Gr + 1)/<wbr/>(mean_<wbr/>Gb + 1),<wbr/> (mean_<wbr/>Gb + 1)/<wbr/>(mean_<wbr/>Gr + 1))</code></li>
-</ol>
-<p>The ratio R is the green split divergence reported for this property,<wbr/>
-which represents how much the green channels differ in the mosaic
-pattern.<wbr/>  This value is typically used to determine the treatment of
-the green mosaic channels when demosaicing.<wbr/></p>
-<p>The green split value can be roughly interpreted as follows:</p>
-<ul>
-<li>R &lt; 1.<wbr/>03 is a negligible split (&lt;3% divergence).<wbr/></li>
-<li>1.<wbr/>20 &lt;= R &gt;= 1.<wbr/>03 will require some software
-correction to avoid demosaic errors (3-20% divergence).<wbr/></li>
-<li>R &gt; 1.<wbr/>20 will require strong software correction to produce
-a usuable image (&gt;20% divergence).<wbr/></li>
-</ul>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The green split given may be a static value based on prior
-characterization of the camera sensor using the green split
-calculation method given here over a large,<wbr/> representative,<wbr/> sample
-set of images.<wbr/>  Other methods of calculation that produce equivalent
-results,<wbr/> and can be interpreted in the same manner,<wbr/> may be used.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.testPatternData">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A pixel <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> that supplies the test pattern
-when <a href="#controls_android.sensor.testPatternMode">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode</a> is SOLID_<wbr/>COLOR.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Each color channel is treated as an unsigned 32-bit integer.<wbr/>
-The camera device then uses the most significant X bits
-that correspond to how many bits are in its Bayer raw sensor
-output.<wbr/></p>
-<p>For example,<wbr/> a sensor with RAW10 Bayer output would use the
-10 most significant bits from each color channel.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.testPatternMode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No test pattern mode is used,<wbr/> and the camera
-device returns captures from the image sensor.<wbr/></p>
-<p>This is the default if the key is not set.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SOLID_COLOR</span>
-                    <span class="entry_type_enum_notes"><p>Each pixel in <code>[R,<wbr/> G_<wbr/>even,<wbr/> G_<wbr/>odd,<wbr/> B]</code> is replaced by its
-respective color channel provided in
-<a href="#controls_android.sensor.testPatternData">android.<wbr/>sensor.<wbr/>test<wbr/>Pattern<wbr/>Data</a>.<wbr/></p>
-<p>For example:</p>
-<pre><code>android.<wbr/>testPatternData = [0,<wbr/> 0xFFFFFFFF,<wbr/> 0xFFFFFFFF,<wbr/> 0]
-</code></pre>
-<p>All green pixels are 100% green.<wbr/> All red/<wbr/>blue pixels are black.<wbr/></p>
-<pre><code>android.<wbr/>testPatternData = [0xFFFFFFFF,<wbr/> 0,<wbr/> 0xFFFFFFFF,<wbr/> 0]
-</code></pre>
-<p>All red pixels are 100% red.<wbr/> Only the odd green pixels
-are 100% green.<wbr/> All blue pixels are 100% black.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">COLOR_BARS</span>
-                    <span class="entry_type_enum_notes"><p>All pixel data is replaced with an 8-bar color pattern.<wbr/></p>
-<p>The vertical bars (left-to-right) are as follows:</p>
-<ul>
-<li>100% white</li>
-<li>yellow</li>
-<li>cyan</li>
-<li>green</li>
-<li>magenta</li>
-<li>red</li>
-<li>blue</li>
-<li>black</li>
-</ul>
-<p>In general the image would look like the following:</p>
-<pre><code>W Y C G M R B K
-W Y C G M R B K
-W Y C G M R B K
-W Y C G M R B K
-W Y C G M R B K
-.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
-.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
-.<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/> .<wbr/>
-
-(B = Blue,<wbr/> K = Black)
-</code></pre>
-<p>Each bar should take up 1/<wbr/>8 of the sensor pixel array width.<wbr/>
-When this is not possible,<wbr/> the bar size should be rounded
-down to the nearest integer and the pattern can repeat
-on the right side.<wbr/></p>
-<p>Each bar's height must always take up the full sensor
-pixel array height.<wbr/></p>
-<p>Each pixel in this test pattern must be set to either
-0% intensity or 100% intensity.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">COLOR_BARS_FADE_TO_GRAY</span>
-                    <span class="entry_type_enum_notes"><p>The test pattern is similar to COLOR_<wbr/>BARS,<wbr/> except that
-each bar should start at its specified color at the top,<wbr/>
-and fade to gray at the bottom.<wbr/></p>
-<p>Furthermore each bar is further subdivided into a left and
-right half.<wbr/> The left half should have a smooth gradient,<wbr/>
-and the right half should have a quantized gradient.<wbr/></p>
-<p>In particular,<wbr/> the right half's should consist of blocks of the
-same color for 1/<wbr/>16th active sensor pixel array width.<wbr/></p>
-<p>The least significant bits in the quantized gradient should
-be copied from the most significant bits of the smooth gradient.<wbr/></p>
-<p>The height of each bar should always be a multiple of 128.<wbr/>
-When this is not the case,<wbr/> the pattern should repeat at the bottom
-of the image.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PN9</span>
-                    <span class="entry_type_enum_notes"><p>All pixel data is replaced by a pseudo-random sequence
-generated from a PN9 512-bit sequence (typically implemented
-in hardware with a linear feedback shift register).<wbr/></p>
-<p>The generator should be reset at the beginning of each frame,<wbr/>
-and thus each subsequent raw frame with this test pattern should
-be exactly the same as the last.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">CUSTOM1</span>
-                    <span class="entry_type_enum_value">256</span>
-                    <span class="entry_type_enum_notes"><p>The first custom test pattern.<wbr/> All custom patterns that are
-available only on this camera device are at least this numeric
-value.<wbr/></p>
-<p>All of the custom test patterns will be static
-(that is the raw image must not vary from frame to frame).<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>When enabled,<wbr/> the sensor sends a test pattern instead of
-doing a real exposure from the camera.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.sensor.availableTestPatternModes">android.<wbr/>sensor.<wbr/>available<wbr/>Test<wbr/>Pattern<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When a test pattern is enabled,<wbr/> all manual sensor controls specified
-by android.<wbr/>sensor.<wbr/>* will be ignored.<wbr/> All other controls should
-work as normal.<wbr/></p>
-<p>For example,<wbr/> if manual flash is enabled,<wbr/> flash firing should still
-occur (and that the test pattern remain unmodified,<wbr/> since the flash
-would not actually affect it).<wbr/></p>
-<p>Defaults to OFF.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>All test patterns are specified in the Bayer domain.<wbr/></p>
-<p>The HAL may choose to substitute test patterns from the sensor
-with test patterns from on-device memory.<wbr/> In that case,<wbr/> it should be
-indistinguishable to the ISP whether the data came from the
-sensor interconnect bus (such as CSI2) or memory.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.rollingShutterSkew">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>rolling<wbr/>Shutter<wbr/>Skew
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Duration between the start of first row exposure
-and the start of last row exposure.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Nanoseconds
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0 and &lt;
-<a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is the exposure time skew between the first and last
-row exposure start times.<wbr/> The first row and the last row are
-the first and last rows inside of the
-<a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-<p>For typical camera sensors that use rolling shutters,<wbr/> this is also equivalent
-to the frame readout time.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The HAL must report <code>0</code> if the sensor is using global shutter,<wbr/> where all pixels begin
-exposure at the same time.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.dynamicBlackLevel">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>dynamic<wbr/>Black<wbr/>Level
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-                <div class="entry_type_notes">2x2 raw count block</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A per-frame dynamic black level offset for each of the color filter
-arrangement (CFA) mosaic channels.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0 for each.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Camera sensor black levels may vary dramatically for different
-capture settings (e.<wbr/>g.<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>).<wbr/> The fixed black
-level reported by <a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> may be too
-inaccurate to represent the actual value on a per-frame basis.<wbr/> The
-camera device internal pipeline relies on reliable black level values
-to process the raw images appropriately.<wbr/> To get the best image
-quality,<wbr/> the camera device may choose to estimate the per frame black
-level values either based on optically shielded black regions
-(<a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a>) or its internal model.<wbr/></p>
-<p>This key reports the camera device estimated per-frame zero light
-value for each of the CFA mosaic channels in the camera sensor.<wbr/> The
-<a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> may only represent a coarse
-approximation of the actual black level values.<wbr/> This value is the
-black level used in camera device internal image processing pipeline
-and generally more accurate than the fixed black level values.<wbr/>
-However,<wbr/> since they are estimated values by the camera device,<wbr/> they
-may not be as accurate as the black level values calculated from the
-optical black pixels reported by <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a>.<wbr/></p>
-<p>The values are given in the same order as channels listed for the CFA
-layout key (see <a href="#static_android.sensor.info.colorFilterArrangement">android.<wbr/>sensor.<wbr/>info.<wbr/>color<wbr/>Filter<wbr/>Arrangement</a>),<wbr/> i.<wbr/>e.<wbr/> the
-nth value given corresponds to the black level offset for the nth
-color channel listed in the CFA.<wbr/></p>
-<p>This key will be available if <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> is
-available or the camera device advertises this key via
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureResultKeys">CameraCharacteristics#getAvailableCaptureResultKeys</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The values are given in row-column scan order,<wbr/> with the first value
-corresponding to the element of the CFA in row=0,<wbr/> column=0.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.sensor.dynamicWhiteLevel">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sensor.<wbr/>dynamic<wbr/>White<wbr/>Level
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Maximum raw value output by sensor for this frame.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Since the <a href="#static_android.sensor.blackLevelPattern">android.<wbr/>sensor.<wbr/>black<wbr/>Level<wbr/>Pattern</a> may change for different
-capture settings (e.<wbr/>g.,<wbr/> <a href="#controls_android.sensor.sensitivity">android.<wbr/>sensor.<wbr/>sensitivity</a>),<wbr/> the white
-level will change accordingly.<wbr/> This key is similar to
-<a href="#static_android.sensor.info.whiteLevel">android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level</a>,<wbr/> but specifies the camera device
-estimated white level for each frame.<wbr/></p>
-<p>This key will be available if <a href="#static_android.sensor.opticalBlackRegions">android.<wbr/>sensor.<wbr/>optical<wbr/>Black<wbr/>Regions</a> is
-available or the camera device advertises this key via
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#getAvailableCaptureRequestKeys">CameraCharacteristics#getAvailableCaptureRequestKeys</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The full bit depth of the sensor must be available in the raw data,<wbr/>
-so the value for linear sensors should not be significantly lower
-than maximum raw value supported,<wbr/> i.<wbr/>e.<wbr/> 2^(sensor bits per pixel).<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_shading" class="section">shading</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.shading.mode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>shading.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No lens shading correction is applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Apply lens shading corrections,<wbr/> without slowing
-frame rate relative to sensor raw output</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>Apply high-quality lens shading correction,<wbr/> at the
-cost of possibly reduced frame rate.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Quality of lens shading correction applied
-to the image data.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.shading.availableModes">android.<wbr/>shading.<wbr/>available<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to OFF mode,<wbr/> no lens shading correction will be applied by the
-camera device,<wbr/> and an identity lens shading map data will be provided
-if <code><a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> == ON</code>.<wbr/> For example,<wbr/> for lens
-shading map with size of <code>[ 4,<wbr/> 3 ]</code>,<wbr/>
-the output <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a> for this case will be an identity
-map shown below:</p>
-<pre><code>[ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
- 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
- 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
- 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
- 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
- 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ]
-</code></pre>
-<p>When set to other modes,<wbr/> lens shading correction will be applied by the camera
-device.<wbr/> Applications can request lens shading map data by setting
-<a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> to ON,<wbr/> and then the camera device will provide lens
-shading map data in <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a>; the returned shading map
-data will be the one applied by the camera device for this capture request.<wbr/></p>
-<p>The shading map data may depend on the auto-exposure (AE) and AWB statistics,<wbr/> therefore
-the reliability of the map data may be affected by the AE and AWB algorithms.<wbr/> When AE and
-AWB are in AUTO modes(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF and <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>!=</code>
-OFF),<wbr/> to get best results,<wbr/> it is recommended that the applications wait for the AE and AWB
-to be converged before using the returned shading map data.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.shading.strength">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>shading.<wbr/>strength
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Control the amount of shading correction
-applied to the images</p>
-            </td>
-
-            <td class="entry_units">
-              unitless: 1-10; 10 is full shading
-          compensation
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.shading.mode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>shading.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>No lens shading correction is applied.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Apply lens shading corrections,<wbr/> without slowing
-frame rate relative to sensor raw output</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>Apply high-quality lens shading correction,<wbr/> at the
-cost of possibly reduced frame rate.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Quality of lens shading correction applied
-to the image data.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.shading.availableModes">android.<wbr/>shading.<wbr/>available<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to OFF mode,<wbr/> no lens shading correction will be applied by the
-camera device,<wbr/> and an identity lens shading map data will be provided
-if <code><a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> == ON</code>.<wbr/> For example,<wbr/> for lens
-shading map with size of <code>[ 4,<wbr/> 3 ]</code>,<wbr/>
-the output <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a> for this case will be an identity
-map shown below:</p>
-<pre><code>[ 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
- 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
- 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
- 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
- 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>
- 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ]
-</code></pre>
-<p>When set to other modes,<wbr/> lens shading correction will be applied by the camera
-device.<wbr/> Applications can request lens shading map data by setting
-<a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> to ON,<wbr/> and then the camera device will provide lens
-shading map data in <a href="#dynamic_android.statistics.lensShadingCorrectionMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map</a>; the returned shading map
-data will be the one applied by the camera device for this capture request.<wbr/></p>
-<p>The shading map data may depend on the auto-exposure (AE) and AWB statistics,<wbr/> therefore
-the reliability of the map data may be affected by the AE and AWB algorithms.<wbr/> When AE and
-AWB are in AUTO modes(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF and <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>!=</code>
-OFF),<wbr/> to get best results,<wbr/> it is recommended that the applications wait for the AE and AWB
-to be converged before using the returned shading map data.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.shading.availableModes">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>shading.<wbr/>available<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">List of enums (android.<wbr/>shading.<wbr/>mode).<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of lens shading modes for <a href="#controls_android.shading.mode">android.<wbr/>shading.<wbr/>mode</a> that are supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.shading.mode">android.<wbr/>shading.<wbr/>mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This list contains lens shading modes that can be set for the camera device.<wbr/>
-Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always
-list OFF and FAST mode.<wbr/> This includes all FULL level devices.<wbr/>
-LEGACY devices will always only support FAST mode.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if lens shading correction control is
-available on the camera device,<wbr/> but the underlying implementation can be the same for
-both modes.<wbr/> That is,<wbr/> if the highest quality implementation on the camera device does not
-slow down capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_statistics" class="section">statistics</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.statistics.faceDetectMode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Do not include face detection statistics in capture
-results.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SIMPLE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Return face rectangle and confidence values only.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FULL</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Return all face
-metadata.<wbr/></p>
-<p>In this mode,<wbr/> face rectangles,<wbr/> scores,<wbr/> landmarks,<wbr/> and face IDs are all valid.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operating mode for the face detector
-unit.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.statistics.info.availableFaceDetectModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Whether face detection is enabled,<wbr/> and whether it
-should output just the basic fields or the full set of
-fields.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>SIMPLE mode must fill in <a href="#dynamic_android.statistics.faceRectangles">android.<wbr/>statistics.<wbr/>face<wbr/>Rectangles</a> and
-<a href="#dynamic_android.statistics.faceScores">android.<wbr/>statistics.<wbr/>face<wbr/>Scores</a>.<wbr/>
-FULL mode must also fill in <a href="#dynamic_android.statistics.faceIds">android.<wbr/>statistics.<wbr/>face<wbr/>Ids</a>,<wbr/> and
-<a href="#dynamic_android.statistics.faceLandmarks">android.<wbr/>statistics.<wbr/>face<wbr/>Landmarks</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.statistics.histogramMode">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>statistics.<wbr/>histogram<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [system as boolean]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operating mode for histogram
-generation</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.statistics.sharpnessMapMode">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>statistics.<wbr/>sharpness<wbr/>Map<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [system as boolean]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operating mode for sharpness map
-generation</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.statistics.hotPixelMapMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Hot pixel map production is disabled.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>Hot pixel map production is enabled.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operating mode for hot pixel map generation.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.statistics.info.availableHotPixelMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Map<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If set to <code>true</code>,<wbr/> a hot pixel map is returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/>
-If set to <code>false</code>,<wbr/> no hot pixel map will be returned.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.statistics.lensShadingMapMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Do not include a lens shading map in the capture result.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>Include a lens shading map in the capture result.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether the camera device will output the lens
-shading map in output result metadata.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.statistics.info.availableLensShadingMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Lens<wbr/>Shading<wbr/>Map<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to ON,<wbr/>
-<a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> will be provided in
-the output result metadata.<wbr/></p>
-<p>ON is always supported on devices with the RAW capability.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-                
-            
-
-                
-          <tr class="entry" id="static_android.statistics.info.availableFaceDetectModes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">List of enums from android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of face detection modes for <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> that are
-supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>OFF is always supported.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.statistics.info.histogramBucketCount">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>statistics.<wbr/>info.<wbr/>histogram<wbr/>Bucket<wbr/>Count
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Number of histogram buckets
-supported</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 64</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.statistics.info.maxFaceCount">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Face<wbr/>Count
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum number of simultaneously detectable
-faces.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>0 for cameras without available face detection; otherwise:
-<code>&gt;=4</code> for LIMITED or FULL hwlevel devices or
-<code>&gt;0</code> for LEGACY devices.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.statistics.info.maxHistogramCount">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Histogram<wbr/>Count
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Maximum value possible for a histogram
-bucket</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.statistics.info.maxSharpnessMapValue">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>statistics.<wbr/>info.<wbr/>max<wbr/>Sharpness<wbr/>Map<wbr/>Value
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Maximum value possible for a sharpness map
-region.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.statistics.info.sharpnessMapSize">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>statistics.<wbr/>info.<wbr/>sharpness<wbr/>Map<wbr/>Size
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2
-                </span>
-              <span class="entry_type_visibility"> [system as size]</span>
-
-
-
-
-                <div class="entry_type_notes">width x height</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Dimensions of the sharpness
-map</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Must be at least 32 x 32</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.statistics.info.availableHotPixelMapModes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Map<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of hot pixel map output modes for <a href="#controls_android.statistics.hotPixelMapMode">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode</a> that are
-supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.statistics.hotPixelMapMode">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If no hotpixel map output is available for this camera device,<wbr/> this will contain only
-<code>false</code>.<wbr/></p>
-<p>ON is always supported on devices with the RAW capability.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.statistics.info.availableLensShadingMapModes">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Lens<wbr/>Shading<wbr/>Map<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of lens shading map output modes for <a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a> that
-are supported by this camera device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.statistics.lensShadingMapMode">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If no lens shading map output is available for this camera device,<wbr/> this key will
-contain only OFF.<wbr/></p>
-<p>ON is always supported on devices with the RAW capability.<wbr/>
-LEGACY mode devices will always only support OFF.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-        
-
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.statistics.faceDetectMode">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Do not include face detection statistics in capture
-results.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">SIMPLE</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Return face rectangle and confidence values only.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FULL</span>
-                    <span class="entry_type_enum_optional">[optional]</span>
-                    <span class="entry_type_enum_notes"><p>Return all face
-metadata.<wbr/></p>
-<p>In this mode,<wbr/> face rectangles,<wbr/> scores,<wbr/> landmarks,<wbr/> and face IDs are all valid.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operating mode for the face detector
-unit.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.statistics.info.availableFaceDetectModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Whether face detection is enabled,<wbr/> and whether it
-should output just the basic fields or the full set of
-fields.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>SIMPLE mode must fill in <a href="#dynamic_android.statistics.faceRectangles">android.<wbr/>statistics.<wbr/>face<wbr/>Rectangles</a> and
-<a href="#dynamic_android.statistics.faceScores">android.<wbr/>statistics.<wbr/>face<wbr/>Scores</a>.<wbr/>
-FULL mode must also fill in <a href="#dynamic_android.statistics.faceIds">android.<wbr/>statistics.<wbr/>face<wbr/>Ids</a>,<wbr/> and
-<a href="#dynamic_android.statistics.faceLandmarks">android.<wbr/>statistics.<wbr/>face<wbr/>Landmarks</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.faceIds">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>face<wbr/>Ids
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of unique IDs for detected faces.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Each detected face is given a unique ID that is valid for as long as the face is visible
-to the camera device.<wbr/>  A face that leaves the field of view and later returns may be
-assigned a new ID.<wbr/></p>
-<p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> == FULL</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.faceLandmarks">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>face<wbr/>Landmarks
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 6
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">(leftEyeX,<wbr/> leftEyeY,<wbr/> rightEyeX,<wbr/> rightEyeY,<wbr/> mouthX,<wbr/> mouthY)</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of landmarks for detected
-faces.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The coordinate system is that of <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with
-<code>(0,<wbr/> 0)</code> being the top-left pixel of the active array.<wbr/></p>
-<p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> == FULL</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.faceRectangles">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>face<wbr/>Rectangles
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 4
-                </span>
-              <span class="entry_type_visibility"> [ndk_public as rectangle]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-                <div class="entry_type_notes">(xmin,<wbr/> ymin,<wbr/> xmax,<wbr/> ymax).<wbr/> (0,<wbr/>0) is top-left of active pixel area</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of the bounding rectangles for detected
-faces.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The coordinate system is that of <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>,<wbr/> with
-<code>(0,<wbr/> 0)</code> being the top-left pixel of the active array.<wbr/></p>
-<p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> != OFF</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.faceScores">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>statistics.<wbr/>face<wbr/>Scores
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of the face confidence scores for
-detected faces</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>1-100</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_BC">BC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> != OFF.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The value should be meaningful (for example,<wbr/> setting 100 at
-all times is illegal).<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.faces">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>faces
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [java_public as face]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of the faces detected through camera face detection
-in this capture.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Only available if <a href="#controls_android.statistics.faceDetectMode">android.<wbr/>statistics.<wbr/>face<wbr/>Detect<wbr/>Mode</a> <code>!=</code> OFF.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.histogram">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>histogram
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 3
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-                <div class="entry_type_notes">count of pixels for each color channel that fall into each histogram bucket,<wbr/> scaled to be between 0 and maxHistogramCount</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A 3-channel histogram based on the raw
-sensor data</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The k'th bucket (0-based) covers the input range
-(with w = <a href="#static_android.sensor.info.whiteLevel">android.<wbr/>sensor.<wbr/>info.<wbr/>white<wbr/>Level</a>) of [ k * w/<wbr/>N,<wbr/>
-(k + 1) * w /<wbr/> N ).<wbr/> If only a monochrome sharpness map is
-supported,<wbr/> all channels should have the same data</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.histogramMode">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>statistics.<wbr/>histogram<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [system as boolean]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operating mode for histogram
-generation</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.sharpnessMap">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>sharpness<wbr/>Map
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x m x 3
-                </span>
-              <span class="entry_type_visibility"> [system]</span>
-
-
-
-
-                <div class="entry_type_notes">estimated sharpness for each region of the input image.<wbr/> Normalized to be between 0 and maxSharpnessMapValue.<wbr/> Higher values mean sharper (better focused)</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A 3-channel sharpness map,<wbr/> based on the raw
-sensor data</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If only a monochrome sharpness map is supported,<wbr/>
-all channels should have the same data</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.sharpnessMapMode">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>statistics.<wbr/>sharpness<wbr/>Map<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [system as boolean]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operating mode for sharpness map
-generation</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_FUTURE">FUTURE</a></li>
-              </ul>
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.lensShadingCorrectionMap">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Correction<wbr/>Map
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-
-              <span class="entry_type_visibility"> [java_public as lensShadingMap]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The shading map is a low-resolution floating-point map
-that lists the coefficients used to correct for vignetting,<wbr/> for each
-Bayer color channel.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Each gain factor is &gt;= 1</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The map provided here is the same map that is used by the camera device to
-correct both color shading and vignetting for output non-RAW images.<wbr/></p>
-<p>When there is no lens shading correction applied to RAW
-output images (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a> <code>==</code>
-false),<wbr/> this map is the complete lens shading correction
-map; when there is some lens shading correction applied to
-the RAW output image (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a><code>==</code> true),<wbr/> this map reports the remaining lens shading
-correction map that needs to be applied to get shading
-corrected images that match the camera device's output for
-non-RAW formats.<wbr/></p>
-<p>For a complete shading correction map,<wbr/> the least shaded
-section of the image will have a gain factor of 1; all
-other sections will have gains above 1.<wbr/></p>
-<p>When <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> = TRANSFORM_<wbr/>MATRIX,<wbr/> the map
-will take into account the colorCorrection settings.<wbr/></p>
-<p>The shading map is for the entire active pixel array,<wbr/> and is not
-affected by the crop region specified in the request.<wbr/> Each shading map
-entry is the value of the shading compensation map over a specific
-pixel on the sensor.<wbr/>  Specifically,<wbr/> with a (N x M) resolution shading
-map,<wbr/> and an active pixel array size (W x H),<wbr/> shading map entry
-(x,<wbr/>y) ϵ (0 ...<wbr/> N-1,<wbr/> 0 ...<wbr/> M-1) is the value of the shading map at
-pixel ( ((W-1)/<wbr/>(N-1)) * x,<wbr/> ((H-1)/<wbr/>(M-1)) * y) for the four color channels.<wbr/>
-The map is assumed to be bilinearly interpolated between the sample points.<wbr/></p>
-<p>The channel order is [R,<wbr/> Geven,<wbr/> Godd,<wbr/> B],<wbr/> where Geven is the green
-channel for the even rows of a Bayer pattern,<wbr/> and Godd is the odd rows.<wbr/>
-The shading map is stored in a fully interleaved format.<wbr/></p>
-<p>The shading map will generally have on the order of 30-40 rows and columns,<wbr/>
-and will be smaller than 64x64.<wbr/></p>
-<p>As an example,<wbr/> given a very small map defined as:</p>
-<pre><code>width,<wbr/>height = [ 4,<wbr/> 3 ]
-values =
-[ 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/>  1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/>
-    1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/>  1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>3,<wbr/>
-  1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>1,<wbr/>  1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/>
-    1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>2,<wbr/>
-  1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/>   1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/>
-    1.<wbr/>2,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>2,<wbr/>  1.<wbr/>3,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3 ]
-</code></pre>
-<p>The low-resolution scaling map images for each channel are
-(displayed using nearest-neighbor interpolation):</p>
-<p><img alt="Red lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png"/>
-<img alt="Green (even rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png"/>
-<img alt="Green (odd rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png"/>
-<img alt="Blue lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png"/></p>
-<p>As a visualization only,<wbr/> inverting the full-color map to recover an
-image of a gray wall (using bicubic interpolation for visual quality) as captured by the sensor gives:</p>
-<p><img alt="Image of a uniform white wall (inverse shading map)" src="images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png"/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.lensShadingMap">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4 x n x m
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">2D array of float gain factors per channel to correct lens shading</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The shading map is a low-resolution floating-point map
-that lists the coefficients used to correct for vignetting and color shading,<wbr/>
-for each Bayer color channel of RAW image data.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Each gain factor is &gt;= 1</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The map provided here is the same map that is used by the camera device to
-correct both color shading and vignetting for output non-RAW images.<wbr/></p>
-<p>When there is no lens shading correction applied to RAW
-output images (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a> <code>==</code>
-false),<wbr/> this map is the complete lens shading correction
-map; when there is some lens shading correction applied to
-the RAW output image (<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a><code>==</code> true),<wbr/> this map reports the remaining lens shading
-correction map that needs to be applied to get shading
-corrected images that match the camera device's output for
-non-RAW formats.<wbr/></p>
-<p>For a complete shading correction map,<wbr/> the least shaded
-section of the image will have a gain factor of 1; all
-other sections will have gains above 1.<wbr/></p>
-<p>When <a href="#controls_android.colorCorrection.mode">android.<wbr/>color<wbr/>Correction.<wbr/>mode</a> = TRANSFORM_<wbr/>MATRIX,<wbr/> the map
-will take into account the colorCorrection settings.<wbr/></p>
-<p>The shading map is for the entire active pixel array,<wbr/> and is not
-affected by the crop region specified in the request.<wbr/> Each shading map
-entry is the value of the shading compensation map over a specific
-pixel on the sensor.<wbr/>  Specifically,<wbr/> with a (N x M) resolution shading
-map,<wbr/> and an active pixel array size (W x H),<wbr/> shading map entry
-(x,<wbr/>y) ϵ (0 ...<wbr/> N-1,<wbr/> 0 ...<wbr/> M-1) is the value of the shading map at
-pixel ( ((W-1)/<wbr/>(N-1)) * x,<wbr/> ((H-1)/<wbr/>(M-1)) * y) for the four color channels.<wbr/>
-The map is assumed to be bilinearly interpolated between the sample points.<wbr/></p>
-<p>The channel order is [R,<wbr/> Geven,<wbr/> Godd,<wbr/> B],<wbr/> where Geven is the green
-channel for the even rows of a Bayer pattern,<wbr/> and Godd is the odd rows.<wbr/>
-The shading map is stored in a fully interleaved format,<wbr/> and its size
-is provided in the camera static metadata by <a href="#static_android.lens.info.shadingMapSize">android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size</a>.<wbr/></p>
-<p>The shading map will generally have on the order of 30-40 rows and columns,<wbr/>
-and will be smaller than 64x64.<wbr/></p>
-<p>As an example,<wbr/> given a very small map defined as:</p>
-<pre><code><a href="#static_android.lens.info.shadingMapSize">android.<wbr/>lens.<wbr/>info.<wbr/>shading<wbr/>Map<wbr/>Size</a> = [ 4,<wbr/> 3 ]
-<a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> =
-[ 1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/>  1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/>
-    1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/>  1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>3,<wbr/>
-  1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>1,<wbr/>  1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/>
-    1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/>  1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/> 1.<wbr/>25,<wbr/> 1.<wbr/>2,<wbr/>
-  1.<wbr/>3,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3,<wbr/>   1.<wbr/>2,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>2,<wbr/>
-    1.<wbr/>2,<wbr/> 1.<wbr/>1,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>2,<wbr/>  1.<wbr/>3,<wbr/> 1.<wbr/>15,<wbr/> 1.<wbr/>2,<wbr/> 1.<wbr/>3 ]
-</code></pre>
-<p>The low-resolution scaling map images for each channel are
-(displayed using nearest-neighbor interpolation):</p>
-<p><img alt="Red lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png"/>
-<img alt="Green (even rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png"/>
-<img alt="Green (odd rows) lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png"/>
-<img alt="Blue lens shading map" src="images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png"/></p>
-<p>As a visualization only,<wbr/> inverting the full-color map to recover an
-image of a gray wall (using bicubic interpolation for visual quality)
-as captured by the sensor gives:</p>
-<p><img alt="Image of a uniform white wall (inverse shading map)" src="images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png"/></p>
-<p>Note that the RAW image data might be subject to lens shading
-correction not reported on this map.<wbr/> Query
-<a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a> to see if RAW image data has subject
-to lens shading correction.<wbr/> If <a href="#static_android.sensor.info.lensShadingApplied">android.<wbr/>sensor.<wbr/>info.<wbr/>lens<wbr/>Shading<wbr/>Applied</a>
-is TRUE,<wbr/> the RAW image data is subject to partial or full lens shading
-correction.<wbr/> In the case full lens shading correction is applied to RAW
-images,<wbr/> the gain factor map reported in this key will contain all 1.<wbr/>0 gains.<wbr/>
-In other words,<wbr/> the map reported in this key is the remaining lens shading
-that needs to be applied on the RAW image to get images without lens shading
-artifacts.<wbr/> See <a href="#static_android.request.maxNumOutputRaw">android.<wbr/>request.<wbr/>max<wbr/>Num<wbr/>Output<wbr/>Raw</a> for a list of RAW image
-formats.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The lens shading map calculation may depend on exposure and white balance statistics.<wbr/>
-When AE and AWB are in AUTO modes
-(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>!=</code> OFF and <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>!=</code> OFF),<wbr/> the HAL
-may have all the information it need to generate most accurate lens shading map.<wbr/> When
-AE or AWB are in manual mode
-(<a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> <code>==</code> OFF or <a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a> <code>==</code> OFF),<wbr/> the shading map
-may be adversely impacted by manual exposure or white balance parameters.<wbr/> To avoid
-generating unreliable shading map data,<wbr/> the HAL may choose to lock the shading map with
-the latest known good map generated when the AE and AWB are in AUTO modes.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.predictedColorGains">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>predicted<wbr/>Color<wbr/>Gains
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4
-                </span>
-              <span class="entry_type_visibility"> [hidden]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-                <div class="entry_type_notes">A 1D array of floats for 4 color channel gains</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The best-fit color channel gains calculated
-by the camera device's statistics units for the current output frame.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This may be different than the gains used for this frame,<wbr/>
-since statistics processing on data from a new frame
-typically completes after the transform has already been
-applied to that frame.<wbr/></p>
-<p>The 4 channel gains are defined in Bayer domain,<wbr/>
-see <a href="#controls_android.colorCorrection.gains">android.<wbr/>color<wbr/>Correction.<wbr/>gains</a> for details.<wbr/></p>
-<p>This value should always be calculated by the auto-white balance (AWB) block,<wbr/>
-regardless of the android.<wbr/>control.<wbr/>* current values.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.predictedColorTransform">
-            <td class="entry_name
-                entry_name_deprecated
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>predicted<wbr/>Color<wbr/>Transform
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">rational</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  3 x 3
-                </span>
-              <span class="entry_type_visibility"> [hidden]</span>
-
-
-
-              <span class="entry_type_deprecated">[deprecated] </span>
-
-                <div class="entry_type_notes">3x3 rational matrix in row-major order</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The best-fit color transform matrix estimate
-calculated by the camera device's statistics units for the current
-output frame.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><span class="entry_range_deprecated">Deprecated</span>. Do not use.</p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The camera device will provide the estimate from its
-statistics unit on the white balance transforms to use
-for the next frame.<wbr/> These are the values the camera device believes
-are the best fit for the current output frame.<wbr/> This may
-be different than the transform used for this frame,<wbr/> since
-statistics processing on data from a new frame typically
-completes after the transform has already been applied to
-that frame.<wbr/></p>
-<p>These estimates must be provided for all frames,<wbr/> even if
-capture settings and color transforms are set by the application.<wbr/></p>
-<p>This value should always be calculated by the auto-white balance (AWB) block,<wbr/>
-regardless of the android.<wbr/>control.<wbr/>* current values.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.sceneFlicker">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>scene<wbr/>Flicker
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">NONE</span>
-                    <span class="entry_type_enum_notes"><p>The camera device does not detect any flickering illumination
-in the current scene.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">50HZ</span>
-                    <span class="entry_type_enum_notes"><p>The camera device detects illumination flickering at 50Hz
-in the current scene.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">60HZ</span>
-                    <span class="entry_type_enum_notes"><p>The camera device detects illumination flickering at 60Hz
-in the current scene.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The camera device estimated scene illumination lighting
-frequency.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Many light sources,<wbr/> such as most fluorescent lights,<wbr/> flicker at a rate
-that depends on the local utility power standards.<wbr/> This flicker must be
-accounted for by auto-exposure routines to avoid artifacts in captured images.<wbr/>
-The camera device uses this entry to tell the application what the scene
-illuminant frequency is.<wbr/></p>
-<p>When manual exposure control is enabled
-(<code><a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a> == OFF</code> or <code><a href="#controls_android.control.mode">android.<wbr/>control.<wbr/>mode</a> ==
-OFF</code>),<wbr/> the <a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> doesn't perform
-antibanding,<wbr/> and the application can ensure it selects
-exposure times that do not cause banding issues by looking
-into this metadata field.<wbr/> See
-<a href="#controls_android.control.aeAntibandingMode">android.<wbr/>control.<wbr/>ae<wbr/>Antibanding<wbr/>Mode</a> for more details.<wbr/></p>
-<p>Reports NONE if there doesn't appear to be flickering illumination.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.hotPixelMapMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Hot pixel map production is disabled.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>Hot pixel map production is enabled.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Operating mode for hot pixel map generation.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.statistics.info.availableHotPixelMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Hot<wbr/>Pixel<wbr/>Map<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If set to <code>true</code>,<wbr/> a hot pixel map is returned in <a href="#dynamic_android.statistics.hotPixelMap">android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map</a>.<wbr/>
-If set to <code>false</code>,<wbr/> no hot pixel map will be returned.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.hotPixelMap">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>statistics.<wbr/>hot<wbr/>Pixel<wbr/>Map
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  2 x n
-                </span>
-              <span class="entry_type_visibility"> [public as point]</span>
-
-
-
-
-                <div class="entry_type_notes">list of coordinates based on android.<wbr/>sensor.<wbr/>pixel<wbr/>Array<wbr/>Size</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of <code>(x,<wbr/> y)</code> coordinates of hot/<wbr/>defective pixels on the sensor.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>n &lt;= number of pixels on the sensor.<wbr/>
-The <code>(x,<wbr/> y)</code> coordinates must be bounded by
-<a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>A coordinate <code>(x,<wbr/> y)</code> must lie between <code>(0,<wbr/> 0)</code>,<wbr/> and
-<code>(width - 1,<wbr/> height - 1)</code> (inclusive),<wbr/> which are the top-left and
-bottom-right of the pixel array,<wbr/> respectively.<wbr/> The width and
-height dimensions are given in <a href="#static_android.sensor.info.pixelArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>pixel<wbr/>Array<wbr/>Size</a>.<wbr/>
-This may include hot pixels that lie outside of the active array
-bounds given by <a href="#static_android.sensor.info.activeArraySize">android.<wbr/>sensor.<wbr/>info.<wbr/>active<wbr/>Array<wbr/>Size</a>.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>A hotpixel map contains the coordinates of pixels on the camera
-sensor that do report valid values (usually due to defects in
-the camera sensor).<wbr/> This includes pixels that are stuck at certain
-values,<wbr/> or have a response that does not accuractly encode the
-incoming light from the scene.<wbr/></p>
-<p>To avoid performance issues,<wbr/> there should be significantly fewer hot
-pixels than actual pixels on the camera sensor.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.statistics.lensShadingMapMode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map<wbr/>Mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                    <span class="entry_type_enum_notes"><p>Do not include a lens shading map in the capture result.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                    <span class="entry_type_enum_notes"><p>Include a lens shading map in the capture result.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether the camera device will output the lens
-shading map in output result metadata.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.statistics.info.availableLensShadingMapModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Lens<wbr/>Shading<wbr/>Map<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_RAW">RAW</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to ON,<wbr/>
-<a href="#dynamic_android.statistics.lensShadingMap">android.<wbr/>statistics.<wbr/>lens<wbr/>Shading<wbr/>Map</a> will be provided in
-the output result metadata.<wbr/></p>
-<p>ON is always supported on devices with the RAW capability.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_tonemap" class="section">tonemap</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.tonemap.curveBlue">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>tonemap.<wbr/>curve<wbr/>Blue
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 2
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the blue
-channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-CONTRAST_<wbr/>CURVE.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.tonemap.curveGreen">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>tonemap.<wbr/>curve<wbr/>Green
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 2
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the green
-channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-CONTRAST_<wbr/>CURVE.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.tonemap.curveRed">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>tonemap.<wbr/>curve<wbr/>Red
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 2
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the red
-channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-CONTRAST_<wbr/>CURVE.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>0-1 on both input and output coordinates,<wbr/> normalized
-as a floating-point value such that 0 == black and 1 == white.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Each channel's curve is defined by an array of control points:</p>
-<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> =
-  [ P0in,<wbr/> P0out,<wbr/> P1in,<wbr/> P1out,<wbr/> P2in,<wbr/> P2out,<wbr/> P3in,<wbr/> P3out,<wbr/> ...,<wbr/> PNin,<wbr/> PNout ]
-2 &lt;= N &lt;= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre>
-<p>These are sorted in order of increasing <code>Pin</code>; it is
-required that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to
-define a complete mapping.<wbr/> For input values between control points,<wbr/>
-the camera device must linearly interpolate between the control
-points.<wbr/></p>
-<p>Each curve can have an independent number of points,<wbr/> and the number
-of points can be less than max (that is,<wbr/> the request doesn't have to
-always provide a curve with number of points equivalent to
-<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p>
-<p>A few examples,<wbr/> and their corresponding graphical mappings; these
-only specify the red channel and the precision is limited to 4
-digits,<wbr/> for conciseness.<wbr/></p>
-<p>Linear mapping:</p>
-<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ]
-</code></pre>
-<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p>
-<p>Invert mapping:</p>
-<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 0 ]
-</code></pre>
-<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p>
-<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p>
-<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [
-  0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2920,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4002,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4812,<wbr/>
-  0.<wbr/>2667,<wbr/> 0.<wbr/>5484,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6069,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6594,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7072,<wbr/>
-  0.<wbr/>5333,<wbr/> 0.<wbr/>7515,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7928,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8317,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8685,<wbr/>
-  0.<wbr/>8000,<wbr/> 0.<wbr/>9035,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9370,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9691,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ]
-</code></pre>
-<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p>
-<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p>
-<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [
-  0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2864,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4007,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4845,<wbr/>
-  0.<wbr/>2667,<wbr/> 0.<wbr/>5532,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6125,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6652,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7130,<wbr/>
-  0.<wbr/>5333,<wbr/> 0.<wbr/>7569,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7977,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8360,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8721,<wbr/>
-  0.<wbr/>8000,<wbr/> 0.<wbr/>9063,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9389,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9701,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ]
-</code></pre>
-<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For good quality of mapping,<wbr/> at least 128 control points are
-preferred.<wbr/></p>
-<p>A typical use case of this would be a gamma-1/<wbr/>2.<wbr/>2 curve,<wbr/> with as many
-control points used as are available.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.tonemap.curve">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>tonemap.<wbr/>curve
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [java_public as tonemapCurve]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a>
-is CONTRAST_<wbr/>CURVE.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The tonemapCurve consist of three curves for each of red,<wbr/> green,<wbr/> and blue
-channels respectively.<wbr/> The following example uses the red channel as an
-example.<wbr/> The same logic applies to green and blue channel.<wbr/>
-Each channel's curve is defined by an array of control points:</p>
-<pre><code>curveRed =
-  [ P0(in,<wbr/> out),<wbr/> P1(in,<wbr/> out),<wbr/> P2(in,<wbr/> out),<wbr/> P3(in,<wbr/> out),<wbr/> ...,<wbr/> PN(in,<wbr/> out) ]
-2 &lt;= N &lt;= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre>
-<p>These are sorted in order of increasing <code>Pin</code>; it is always
-guaranteed that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to
-define a complete mapping.<wbr/> For input values between control points,<wbr/>
-the camera device must linearly interpolate between the control
-points.<wbr/></p>
-<p>Each curve can have an independent number of points,<wbr/> and the number
-of points can be less than max (that is,<wbr/> the request doesn't have to
-always provide a curve with number of points equivalent to
-<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p>
-<p>A few examples,<wbr/> and their corresponding graphical mappings; these
-only specify the red channel and the precision is limited to 4
-digits,<wbr/> for conciseness.<wbr/></p>
-<p>Linear mapping:</p>
-<pre><code>curveRed = [ (0,<wbr/> 0),<wbr/> (1.<wbr/>0,<wbr/> 1.<wbr/>0) ]
-</code></pre>
-<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p>
-<p>Invert mapping:</p>
-<pre><code>curveRed = [ (0,<wbr/> 1.<wbr/>0),<wbr/> (1.<wbr/>0,<wbr/> 0) ]
-</code></pre>
-<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p>
-<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p>
-<pre><code>curveRed = [
-  (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2920),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4002),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4812),<wbr/>
-  (0.<wbr/>2667,<wbr/> 0.<wbr/>5484),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6069),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6594),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7072),<wbr/>
-  (0.<wbr/>5333,<wbr/> 0.<wbr/>7515),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7928),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8317),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8685),<wbr/>
-  (0.<wbr/>8000,<wbr/> 0.<wbr/>9035),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9370),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9691),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ]
-</code></pre>
-<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p>
-<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p>
-<pre><code>curveRed = [
-  (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2864),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4007),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4845),<wbr/>
-  (0.<wbr/>2667,<wbr/> 0.<wbr/>5532),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6125),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6652),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7130),<wbr/>
-  (0.<wbr/>5333,<wbr/> 0.<wbr/>7569),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7977),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8360),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8721),<wbr/>
-  (0.<wbr/>8000,<wbr/> 0.<wbr/>9063),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9389),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9701),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ]
-</code></pre>
-<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This entry is created by the framework from the curveRed,<wbr/> curveGreen and
-curveBlue entries.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.tonemap.mode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>tonemap.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">CONTRAST_CURVE</span>
-                    <span class="entry_type_enum_notes"><p>Use the tone mapping curve specified in
-the <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>* entries.<wbr/></p>
-<p>All color enhancement and tonemapping must be disabled,<wbr/> except
-for applying the tonemapping curve specified by
-<a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/></p>
-<p>Must not slow down frame rate relative to raw
-sensor output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Advanced gamma mapping and color enhancement may be applied,<wbr/> without
-reducing frame rate compared to raw sensor output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>High-quality gamma mapping and color enhancement will be applied,<wbr/> at
-the cost of possibly reduced frame rate compared to raw sensor output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">GAMMA_VALUE</span>
-                    <span class="entry_type_enum_notes"><p>Use the gamma value specified in <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a> to peform
-tonemapping.<wbr/></p>
-<p>All color enhancement and tonemapping must be disabled,<wbr/> except
-for applying the tonemapping curve specified by <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a>.<wbr/></p>
-<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PRESET_CURVE</span>
-                    <span class="entry_type_enum_notes"><p>Use the preset tonemapping curve specified in
-<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a> to peform tonemapping.<wbr/></p>
-<p>All color enhancement and tonemapping must be disabled,<wbr/> except
-for applying the tonemapping curve specified by
-<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a>.<wbr/></p>
-<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>High-level global contrast/<wbr/>gamma/<wbr/>tonemapping control.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.tonemap.availableToneMapModes">android.<wbr/>tonemap.<wbr/>available<wbr/>Tone<wbr/>Map<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When switching to an application-defined contrast curve by setting
-<a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> to CONTRAST_<wbr/>CURVE,<wbr/> the curve is defined
-per-channel with a set of <code>(in,<wbr/> out)</code> points that specify the
-mapping from input high-bit-depth pixel value to the output
-low-bit-depth value.<wbr/>  Since the actual pixel ranges of both input
-and output may change depending on the camera pipeline,<wbr/> the values
-are specified by normalized floating-point numbers.<wbr/></p>
-<p>More-complex color mapping operations such as 3D color look-up
-tables,<wbr/> selective chroma enhancement,<wbr/> or other non-linear color
-transforms will be disabled when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-CONTRAST_<wbr/>CURVE.<wbr/></p>
-<p>When using either FAST or HIGH_<wbr/>QUALITY,<wbr/> the camera device will
-emit its own tonemap curve in <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/>
-These values are always available,<wbr/> and as close as possible to the
-actually used nonlinear/<wbr/>nonglobal transforms.<wbr/></p>
-<p>If a request is sent with CONTRAST_<wbr/>CURVE with the camera device's
-provided curve in FAST or HIGH_<wbr/>QUALITY,<wbr/> the image's tonemap will be
-roughly the same.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.tonemap.gamma">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>tonemap.<wbr/>gamma
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-GAMMA_<wbr/>VALUE</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The tonemap curve will be defined the following formula:
-* OUT = pow(IN,<wbr/> 1.<wbr/>0 /<wbr/> gamma)
-where IN and OUT is the input pixel value scaled to range [0.<wbr/>0,<wbr/> 1.<wbr/>0],<wbr/>
-pow is the power function and gamma is the gamma value specified by this
-key.<wbr/></p>
-<p>The same curve will be applied to all color channels.<wbr/> The camera device
-may clip the input gamma value to its supported range.<wbr/> The actual applied
-value will be returned in capture result.<wbr/></p>
-<p>The valid range of gamma value varies on different devices,<wbr/> but values
-within [1.<wbr/>0,<wbr/> 5.<wbr/>0] are guaranteed not to be clipped.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="controls_android.tonemap.presetCurve">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">SRGB</span>
-                    <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by sRGB</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">REC709</span>
-                    <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by ITU-R BT.<wbr/>709</p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-PRESET_<wbr/>CURVE</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The tonemap curve will be defined by specified standard.<wbr/></p>
-<p>sRGB (approximated by 16 control points):</p>
-<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
-<p>Rec.<wbr/> 709 (approximated by 16 control points):</p>
-<p><img alt="Rec. 709 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png"/></p>
-<p>Note that above figures show a 16 control points approximation of preset
-curves.<wbr/> Camera devices may apply a different approximation to the curve.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.tonemap.maxCurvePoints">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Maximum number of supported points in the
-tonemap curve that can be used for <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If the actual number of points provided by the application (in <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>*) is
-less than this maximum,<wbr/> the camera device will resample the curve to its internal
-representation,<wbr/> using linear interpolation.<wbr/></p>
-<p>The output curves in the result metadata may have a different number
-of points than the input curves,<wbr/> and will represent the actual
-hardware curves used as closely as possible when linearly interpolated.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This value must be at least 64.<wbr/> This should be at least 128.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.tonemap.availableToneMapModes">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>tonemap.<wbr/>available<wbr/>Tone<wbr/>Map<wbr/>Modes
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [public as enumList]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">list of enums</div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>List of tonemapping modes for <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> that are supported by this camera
-device.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Any value listed in <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Camera devices that support the MANUAL_<wbr/>POST_<wbr/>PROCESSING capability will always contain
-at least one of below mode combinations:</p>
-<ul>
-<li>CONTRAST_<wbr/>CURVE,<wbr/> FAST and HIGH_<wbr/>QUALITY</li>
-<li>GAMMA_<wbr/>VALUE,<wbr/> PRESET_<wbr/>CURVE,<wbr/> FAST and HIGH_<wbr/>QUALITY</li>
-</ul>
-<p>This includes all FULL level devices.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>HAL must support both FAST and HIGH_<wbr/>QUALITY if automatic tonemap control is available
-on the camera device,<wbr/> but the underlying implementation can be the same for both modes.<wbr/>
-That is,<wbr/> if the highest quality implementation on the camera device does not slow down
-capture rate,<wbr/> then FAST and HIGH_<wbr/>QUALITY will generate the same output.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.tonemap.curveBlue">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>tonemap.<wbr/>curve<wbr/>Blue
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 2
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the blue
-channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-CONTRAST_<wbr/>CURVE.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.tonemap.curveGreen">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>tonemap.<wbr/>curve<wbr/>Green
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 2
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the green
-channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-CONTRAST_<wbr/>CURVE.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>See <a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> for more details.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.tonemap.curveRed">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>tonemap.<wbr/>curve<wbr/>Red
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 2
-                </span>
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-                <div class="entry_type_notes">1D array of float pairs (P_<wbr/>IN,<wbr/> P_<wbr/>OUT).<wbr/> The maximum number of pairs is specified by android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points.<wbr/></div>
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve for the red
-channel,<wbr/> to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-CONTRAST_<wbr/>CURVE.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>0-1 on both input and output coordinates,<wbr/> normalized
-as a floating-point value such that 0 == black and 1 == white.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Each channel's curve is defined by an array of control points:</p>
-<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> =
-  [ P0in,<wbr/> P0out,<wbr/> P1in,<wbr/> P1out,<wbr/> P2in,<wbr/> P2out,<wbr/> P3in,<wbr/> P3out,<wbr/> ...,<wbr/> PNin,<wbr/> PNout ]
-2 &lt;= N &lt;= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre>
-<p>These are sorted in order of increasing <code>Pin</code>; it is
-required that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to
-define a complete mapping.<wbr/> For input values between control points,<wbr/>
-the camera device must linearly interpolate between the control
-points.<wbr/></p>
-<p>Each curve can have an independent number of points,<wbr/> and the number
-of points can be less than max (that is,<wbr/> the request doesn't have to
-always provide a curve with number of points equivalent to
-<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p>
-<p>A few examples,<wbr/> and their corresponding graphical mappings; these
-only specify the red channel and the precision is limited to 4
-digits,<wbr/> for conciseness.<wbr/></p>
-<p>Linear mapping:</p>
-<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0 ]
-</code></pre>
-<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p>
-<p>Invert mapping:</p>
-<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [ 0,<wbr/> 1.<wbr/>0,<wbr/> 1.<wbr/>0,<wbr/> 0 ]
-</code></pre>
-<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p>
-<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p>
-<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [
-  0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2920,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4002,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4812,<wbr/>
-  0.<wbr/>2667,<wbr/> 0.<wbr/>5484,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6069,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6594,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7072,<wbr/>
-  0.<wbr/>5333,<wbr/> 0.<wbr/>7515,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7928,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8317,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8685,<wbr/>
-  0.<wbr/>8000,<wbr/> 0.<wbr/>9035,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9370,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9691,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ]
-</code></pre>
-<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p>
-<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p>
-<pre><code><a href="#controls_android.tonemap.curveRed">android.<wbr/>tonemap.<wbr/>curve<wbr/>Red</a> = [
-  0.<wbr/>0000,<wbr/> 0.<wbr/>0000,<wbr/> 0.<wbr/>0667,<wbr/> 0.<wbr/>2864,<wbr/> 0.<wbr/>1333,<wbr/> 0.<wbr/>4007,<wbr/> 0.<wbr/>2000,<wbr/> 0.<wbr/>4845,<wbr/>
-  0.<wbr/>2667,<wbr/> 0.<wbr/>5532,<wbr/> 0.<wbr/>3333,<wbr/> 0.<wbr/>6125,<wbr/> 0.<wbr/>4000,<wbr/> 0.<wbr/>6652,<wbr/> 0.<wbr/>4667,<wbr/> 0.<wbr/>7130,<wbr/>
-  0.<wbr/>5333,<wbr/> 0.<wbr/>7569,<wbr/> 0.<wbr/>6000,<wbr/> 0.<wbr/>7977,<wbr/> 0.<wbr/>6667,<wbr/> 0.<wbr/>8360,<wbr/> 0.<wbr/>7333,<wbr/> 0.<wbr/>8721,<wbr/>
-  0.<wbr/>8000,<wbr/> 0.<wbr/>9063,<wbr/> 0.<wbr/>8667,<wbr/> 0.<wbr/>9389,<wbr/> 0.<wbr/>9333,<wbr/> 0.<wbr/>9701,<wbr/> 1.<wbr/>0000,<wbr/> 1.<wbr/>0000 ]
-</code></pre>
-<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For good quality of mapping,<wbr/> at least 128 control points are
-preferred.<wbr/></p>
-<p>A typical use case of this would be a gamma-1/<wbr/>2.<wbr/>2 curve,<wbr/> with as many
-control points used as are available.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.tonemap.curve">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>tonemap.<wbr/>curve
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [java_public as tonemapCurve]</span>
-
-              <span class="entry_type_synthetic">[synthetic] </span>
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping /<wbr/> contrast /<wbr/> gamma curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a>
-is CONTRAST_<wbr/>CURVE.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The tonemapCurve consist of three curves for each of red,<wbr/> green,<wbr/> and blue
-channels respectively.<wbr/> The following example uses the red channel as an
-example.<wbr/> The same logic applies to green and blue channel.<wbr/>
-Each channel's curve is defined by an array of control points:</p>
-<pre><code>curveRed =
-  [ P0(in,<wbr/> out),<wbr/> P1(in,<wbr/> out),<wbr/> P2(in,<wbr/> out),<wbr/> P3(in,<wbr/> out),<wbr/> ...,<wbr/> PN(in,<wbr/> out) ]
-2 &lt;= N &lt;= <a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a></code></pre>
-<p>These are sorted in order of increasing <code>Pin</code>; it is always
-guaranteed that input values 0.<wbr/>0 and 1.<wbr/>0 are included in the list to
-define a complete mapping.<wbr/> For input values between control points,<wbr/>
-the camera device must linearly interpolate between the control
-points.<wbr/></p>
-<p>Each curve can have an independent number of points,<wbr/> and the number
-of points can be less than max (that is,<wbr/> the request doesn't have to
-always provide a curve with number of points equivalent to
-<a href="#static_android.tonemap.maxCurvePoints">android.<wbr/>tonemap.<wbr/>max<wbr/>Curve<wbr/>Points</a>).<wbr/></p>
-<p>A few examples,<wbr/> and their corresponding graphical mappings; these
-only specify the red channel and the precision is limited to 4
-digits,<wbr/> for conciseness.<wbr/></p>
-<p>Linear mapping:</p>
-<pre><code>curveRed = [ (0,<wbr/> 0),<wbr/> (1.<wbr/>0,<wbr/> 1.<wbr/>0) ]
-</code></pre>
-<p><img alt="Linear mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png"/></p>
-<p>Invert mapping:</p>
-<pre><code>curveRed = [ (0,<wbr/> 1.<wbr/>0),<wbr/> (1.<wbr/>0,<wbr/> 0) ]
-</code></pre>
-<p><img alt="Inverting mapping curve" src="images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png"/></p>
-<p>Gamma 1/<wbr/>2.<wbr/>2 mapping,<wbr/> with 16 control points:</p>
-<pre><code>curveRed = [
-  (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2920),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4002),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4812),<wbr/>
-  (0.<wbr/>2667,<wbr/> 0.<wbr/>5484),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6069),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6594),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7072),<wbr/>
-  (0.<wbr/>5333,<wbr/> 0.<wbr/>7515),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7928),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8317),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8685),<wbr/>
-  (0.<wbr/>8000,<wbr/> 0.<wbr/>9035),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9370),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9691),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ]
-</code></pre>
-<p><img alt="Gamma = 1/2.2 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png"/></p>
-<p>Standard sRGB gamma mapping,<wbr/> per IEC 61966-2-1:1999,<wbr/> with 16 control points:</p>
-<pre><code>curveRed = [
-  (0.<wbr/>0000,<wbr/> 0.<wbr/>0000),<wbr/> (0.<wbr/>0667,<wbr/> 0.<wbr/>2864),<wbr/> (0.<wbr/>1333,<wbr/> 0.<wbr/>4007),<wbr/> (0.<wbr/>2000,<wbr/> 0.<wbr/>4845),<wbr/>
-  (0.<wbr/>2667,<wbr/> 0.<wbr/>5532),<wbr/> (0.<wbr/>3333,<wbr/> 0.<wbr/>6125),<wbr/> (0.<wbr/>4000,<wbr/> 0.<wbr/>6652),<wbr/> (0.<wbr/>4667,<wbr/> 0.<wbr/>7130),<wbr/>
-  (0.<wbr/>5333,<wbr/> 0.<wbr/>7569),<wbr/> (0.<wbr/>6000,<wbr/> 0.<wbr/>7977),<wbr/> (0.<wbr/>6667,<wbr/> 0.<wbr/>8360),<wbr/> (0.<wbr/>7333,<wbr/> 0.<wbr/>8721),<wbr/>
-  (0.<wbr/>8000,<wbr/> 0.<wbr/>9063),<wbr/> (0.<wbr/>8667,<wbr/> 0.<wbr/>9389),<wbr/> (0.<wbr/>9333,<wbr/> 0.<wbr/>9701),<wbr/> (1.<wbr/>0000,<wbr/> 1.<wbr/>0000) ]
-</code></pre>
-<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This entry is created by the framework from the curveRed,<wbr/> curveGreen and
-curveBlue entries.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.tonemap.mode">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>tonemap.<wbr/>mode
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">CONTRAST_CURVE</span>
-                    <span class="entry_type_enum_notes"><p>Use the tone mapping curve specified in
-the <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>* entries.<wbr/></p>
-<p>All color enhancement and tonemapping must be disabled,<wbr/> except
-for applying the tonemapping curve specified by
-<a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/></p>
-<p>Must not slow down frame rate relative to raw
-sensor output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FAST</span>
-                    <span class="entry_type_enum_notes"><p>Advanced gamma mapping and color enhancement may be applied,<wbr/> without
-reducing frame rate compared to raw sensor output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">HIGH_QUALITY</span>
-                    <span class="entry_type_enum_notes"><p>High-quality gamma mapping and color enhancement will be applied,<wbr/> at
-the cost of possibly reduced frame rate compared to raw sensor output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">GAMMA_VALUE</span>
-                    <span class="entry_type_enum_notes"><p>Use the gamma value specified in <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a> to peform
-tonemapping.<wbr/></p>
-<p>All color enhancement and tonemapping must be disabled,<wbr/> except
-for applying the tonemapping curve specified by <a href="#controls_android.tonemap.gamma">android.<wbr/>tonemap.<wbr/>gamma</a>.<wbr/></p>
-<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">PRESET_CURVE</span>
-                    <span class="entry_type_enum_notes"><p>Use the preset tonemapping curve specified in
-<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a> to peform tonemapping.<wbr/></p>
-<p>All color enhancement and tonemapping must be disabled,<wbr/> except
-for applying the tonemapping curve specified by
-<a href="#controls_android.tonemap.presetCurve">android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve</a>.<wbr/></p>
-<p>Must not slow down frame rate relative to raw sensor output.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>High-level global contrast/<wbr/>gamma/<wbr/>tonemapping control.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p><a href="#static_android.tonemap.availableToneMapModes">android.<wbr/>tonemap.<wbr/>available<wbr/>Tone<wbr/>Map<wbr/>Modes</a></p>
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When switching to an application-defined contrast curve by setting
-<a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> to CONTRAST_<wbr/>CURVE,<wbr/> the curve is defined
-per-channel with a set of <code>(in,<wbr/> out)</code> points that specify the
-mapping from input high-bit-depth pixel value to the output
-low-bit-depth value.<wbr/>  Since the actual pixel ranges of both input
-and output may change depending on the camera pipeline,<wbr/> the values
-are specified by normalized floating-point numbers.<wbr/></p>
-<p>More-complex color mapping operations such as 3D color look-up
-tables,<wbr/> selective chroma enhancement,<wbr/> or other non-linear color
-transforms will be disabled when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-CONTRAST_<wbr/>CURVE.<wbr/></p>
-<p>When using either FAST or HIGH_<wbr/>QUALITY,<wbr/> the camera device will
-emit its own tonemap curve in <a href="#controls_android.tonemap.curve">android.<wbr/>tonemap.<wbr/>curve</a>.<wbr/>
-These values are always available,<wbr/> and as close as possible to the
-actually used nonlinear/<wbr/>nonglobal transforms.<wbr/></p>
-<p>If a request is sent with CONTRAST_<wbr/>CURVE with the camera device's
-provided curve in FAST or HIGH_<wbr/>QUALITY,<wbr/> the image's tonemap will be
-roughly the same.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.tonemap.gamma">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>tonemap.<wbr/>gamma
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-GAMMA_<wbr/>VALUE</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The tonemap curve will be defined the following formula:
-* OUT = pow(IN,<wbr/> 1.<wbr/>0 /<wbr/> gamma)
-where IN and OUT is the input pixel value scaled to range [0.<wbr/>0,<wbr/> 1.<wbr/>0],<wbr/>
-pow is the power function and gamma is the gamma value specified by this
-key.<wbr/></p>
-<p>The same curve will be applied to all color channels.<wbr/> The camera device
-may clip the input gamma value to its supported range.<wbr/> The actual applied
-value will be returned in capture result.<wbr/></p>
-<p>The valid range of gamma value varies on different devices,<wbr/> but values
-within [1.<wbr/>0,<wbr/> 5.<wbr/>0] are guaranteed not to be clipped.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="dynamic_android.tonemap.presetCurve">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>tonemap.<wbr/>preset<wbr/>Curve
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">SRGB</span>
-                    <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by sRGB</p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">REC709</span>
-                    <span class="entry_type_enum_notes"><p>Tonemapping curve is defined by ITU-R BT.<wbr/>709</p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Tonemapping curve to use when <a href="#controls_android.tonemap.mode">android.<wbr/>tonemap.<wbr/>mode</a> is
-PRESET_<wbr/>CURVE</p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The tonemap curve will be defined by specified standard.<wbr/></p>
-<p>sRGB (approximated by 16 control points):</p>
-<p><img alt="sRGB tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png"/></p>
-<p>Rec.<wbr/> 709 (approximated by 16 control points):</p>
-<p><img alt="Rec. 709 tonemapping curve" src="images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png"/></p>
-<p>Note that above figures show a 16 control points approximation of preset
-curves.<wbr/> Camera devices may apply a different approximation to the curve.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_led" class="section">led</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.led.transmit">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>led.<wbr/>transmit
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [hidden as boolean]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>This LED is nominally used to indicate to the user
-that the camera is powered on and may be streaming images back to the
-Application Processor.<wbr/> In certain rare circumstances,<wbr/> the OS may
-disable this when video is processed locally and not transmitted to
-any untrusted applications.<wbr/></p>
-<p>In particular,<wbr/> the LED <em>must</em> always be on when the data could be
-transmitted off the device.<wbr/> The LED <em>should</em> always be on whenever
-data is stored locally on the device.<wbr/></p>
-<p>The LED <em>may</em> be off if a trusted application is using the data that
-doesn't violate the above rules.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.led.transmit">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>led.<wbr/>transmit
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [hidden as boolean]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>This LED is nominally used to indicate to the user
-that the camera is powered on and may be streaming images back to the
-Application Processor.<wbr/> In certain rare circumstances,<wbr/> the OS may
-disable this when video is processed locally and not transmitted to
-any untrusted applications.<wbr/></p>
-<p>In particular,<wbr/> the LED <em>must</em> always be on when the data could be
-transmitted off the device.<wbr/> The LED <em>should</em> always be on whenever
-data is stored locally on the device.<wbr/></p>
-<p>The LED <em>may</em> be off if a trusted application is using the data that
-doesn't violate the above rules.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.led.availableLeds">
-            <td class="entry_name
-             " rowspan="1">
-              android.<wbr/>led.<wbr/>available<wbr/>Leds
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n
-                </span>
-              <span class="entry_type_visibility"> [hidden]</span>
-
-
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">TRANSMIT</span>
-                    <span class="entry_type_enum_notes"><p><a href="#controls_android.led.transmit">android.<wbr/>led.<wbr/>transmit</a> control is used.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>A list of camera LEDs that are available on this system.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_info" class="section">info</td></tr>
-
-
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.info.supportedHardwareLevel">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>info.<wbr/>supported<wbr/>Hardware<wbr/>Level
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">LIMITED</span>
-                    <span class="entry_type_enum_notes"><p>This camera device does not have enough capabilities to qualify as a <code>FULL</code> device or
-better.<wbr/></p>
-<p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code> tables in the
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a> documentation are guaranteed to be supported.<wbr/></p>
-<p>All <code>LIMITED</code> devices support the <code>BACKWARDS_<wbr/>COMPATIBLE</code> capability,<wbr/> indicating basic
-support for color image capture.<wbr/> The only exception is that the device may
-alternatively support only the <code>DEPTH_<wbr/>OUTPUT</code> capability,<wbr/> if it can only output depth
-measurements and not color images.<wbr/></p>
-<p><code>LIMITED</code> devices and above require the use of <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a>
-to lock exposure metering (and calculate flash power,<wbr/> for cameras with flash) before
-capturing a high-quality still image.<wbr/></p>
-<p>A <code>LIMITED</code> device that only lists the <code>BACKWARDS_<wbr/>COMPATIBLE</code> capability is only
-required to support full-automatic operation and post-processing (<code>OFF</code> is not
-supported for <a href="#controls_android.control.aeMode">android.<wbr/>control.<wbr/>ae<wbr/>Mode</a>,<wbr/> <a href="#controls_android.control.afMode">android.<wbr/>control.<wbr/>af<wbr/>Mode</a>,<wbr/> or
-<a href="#controls_android.control.awbMode">android.<wbr/>control.<wbr/>awb<wbr/>Mode</a>)</p>
-<p>Additional capabilities may optionally be supported by a <code>LIMITED</code>-level device,<wbr/> and
-can be checked for in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">FULL</span>
-                    <span class="entry_type_enum_notes"><p>This camera device is capable of supporting advanced imaging applications.<wbr/></p>
-<p>The stream configurations listed in the <code>FULL</code>,<wbr/> <code>LEGACY</code> and <code>LIMITED</code> tables in the
-<a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a> documentation are guaranteed to be supported.<wbr/></p>
-<p>A <code>FULL</code> device will support below capabilities:</p>
-<ul>
-<li><code>BURST_<wbr/>CAPTURE</code> capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains
-  <code>BURST_<wbr/>CAPTURE</code>)</li>
-<li>Per frame control (<a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a> <code>==</code> PER_<wbr/>FRAME_<wbr/>CONTROL)</li>
-<li>Manual sensor control (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains <code>MANUAL_<wbr/>SENSOR</code>)</li>
-<li>Manual post-processing control (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains
-  <code>MANUAL_<wbr/>POST_<wbr/>PROCESSING</code>)</li>
-<li>The required exposure time range defined in <a href="#static_android.sensor.info.exposureTimeRange">android.<wbr/>sensor.<wbr/>info.<wbr/>exposure<wbr/>Time<wbr/>Range</a></li>
-<li>The required maxFrameDuration defined in <a href="#static_android.sensor.info.maxFrameDuration">android.<wbr/>sensor.<wbr/>info.<wbr/>max<wbr/>Frame<wbr/>Duration</a></li>
-</ul>
-<p>Note:
-Pre-API level 23,<wbr/> FULL devices also supported arbitrary cropping region
-(<a href="#static_android.scaler.croppingType">android.<wbr/>scaler.<wbr/>cropping<wbr/>Type</a> <code>== FREEFORM</code>); this requirement was relaxed in API level
-23,<wbr/> and <code>FULL</code> devices may only support <code>CENTERED</code> cropping.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">LEGACY</span>
-                    <span class="entry_type_enum_notes"><p>This camera device is running in backward compatibility mode.<wbr/></p>
-<p>Only the stream configurations listed in the <code>LEGACY</code> table in the <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a>
-documentation are supported.<wbr/></p>
-<p>A <code>LEGACY</code> device does not support per-frame control,<wbr/> manual sensor control,<wbr/> manual
-post-processing,<wbr/> arbitrary cropping regions,<wbr/> and has relaxed performance constraints.<wbr/>
-No additional capabilities beyond <code>BACKWARD_<wbr/>COMPATIBLE</code> will ever be listed by a
-<code>LEGACY</code> device in <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a>.<wbr/></p>
-<p>In addition,<wbr/> the <a href="#controls_android.control.aePrecaptureTrigger">android.<wbr/>control.<wbr/>ae<wbr/>Precapture<wbr/>Trigger</a> is not functional on <code>LEGACY</code>
-devices.<wbr/> Instead,<wbr/> every request that includes a JPEG-format output target is treated
-as triggering a still capture,<wbr/> internally executing a precapture trigger.<wbr/>  This may
-fire the flash for flash power metering during precapture,<wbr/> and then fire the flash
-for the final capture,<wbr/> if a flash is available on the device and the AE mode is set to
-enable the flash.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">3</span>
-                    <span class="entry_type_enum_notes"><p>This camera device is capable of YUV reprocessing and RAW data capture,<wbr/> in addition to
-FULL-level capabilities.<wbr/></p>
-<p>The stream configurations listed in the <code>LEVEL_<wbr/>3</code>,<wbr/> <code>RAW</code>,<wbr/> <code>FULL</code>,<wbr/> <code>LEGACY</code> and
-<code>LIMITED</code> tables in the <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession">createCaptureSession</a>
-documentation are guaranteed to be supported.<wbr/></p>
-<p>The following additional capabilities are guaranteed to be supported:</p>
-<ul>
-<li><code>YUV_<wbr/>REPROCESSING</code> capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains
-  <code>YUV_<wbr/>REPROCESSING</code>)</li>
-<li><code>RAW</code> capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains
-  <code>RAW</code>)</li>
-</ul></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Generally classifies the overall set of the camera device functionality.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The supported hardware level is a high-level description of the camera device's
-capabilities,<wbr/> summarizing several capabilities into one field.<wbr/>  Each level adds additional
-features to the previous one,<wbr/> and is always a strict superset of the previous level.<wbr/>
-The ordering is <code>LEGACY &lt; LIMITED &lt; FULL &lt; LEVEL_<wbr/>3</code>.<wbr/></p>
-<p>Starting from <code>LEVEL_<wbr/>3</code>,<wbr/> the level enumerations are guaranteed to be in increasing
-numerical value as well.<wbr/> To check if a given device is at least at a given hardware level,<wbr/>
-the following code snippet can be used:</p>
-<pre><code>//<wbr/> Returns true if the device supports the required hardware level,<wbr/> or better.<wbr/>
-boolean isHardwareLevelSupported(CameraCharacteristics c,<wbr/> int requiredLevel) {
-    int deviceLevel = c.<wbr/>get(Camera<wbr/>Characteristics.<wbr/>INFO_<wbr/>SUPPORTED_<wbr/>HARDWARE_<wbr/>LEVEL);
-    if (deviceLevel == Camera<wbr/>Characteristics.<wbr/>INFO_<wbr/>SUPPORTED_<wbr/>HARDWARE_<wbr/>LEVEL_<wbr/>LEGACY) {
-        return requiredLevel == deviceLevel;
-    }
-    //<wbr/> deviceLevel is not LEGACY,<wbr/> can use numerical sort
-    return requiredLevel &lt;= deviceLevel;
-}
-</code></pre>
-<p>At a high level,<wbr/> the levels are:</p>
-<ul>
-<li><code>LEGACY</code> devices operate in a backwards-compatibility mode for older
-  Android devices,<wbr/> and have very limited capabilities.<wbr/></li>
-<li><code>LIMITED</code> devices represent the
-  baseline feature set,<wbr/> and may also include additional capabilities that are
-  subsets of <code>FULL</code>.<wbr/></li>
-<li><code>FULL</code> devices additionally support per-frame manual control of sensor,<wbr/> flash,<wbr/> lens and
-  post-processing settings,<wbr/> and image capture at a high rate.<wbr/></li>
-<li><code>LEVEL_<wbr/>3</code> devices additionally support YUV reprocessing and RAW image capture,<wbr/> along
-  with additional output stream configurations.<wbr/></li>
-</ul>
-<p>See the individual level enums for full descriptions of the supported capabilities.<wbr/>  The
-<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> entry describes the device's capabilities at a
-finer-grain level,<wbr/> if needed.<wbr/> In addition,<wbr/> many controls have their available settings or
-ranges defined in individual <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html">CameraCharacteristics</a> entries.<wbr/></p>
-<p>Some features are not part of any particular hardware level or capability and must be
-queried separately.<wbr/> These include:</p>
-<ul>
-<li>Calibrated timestamps (<a href="#static_android.sensor.info.timestampSource">android.<wbr/>sensor.<wbr/>info.<wbr/>timestamp<wbr/>Source</a> <code>==</code> REALTIME)</li>
-<li>Precision lens control (<a href="#static_android.lens.info.focusDistanceCalibration">android.<wbr/>lens.<wbr/>info.<wbr/>focus<wbr/>Distance<wbr/>Calibration</a> <code>==</code> CALIBRATED)</li>
-<li>Face detection (<a href="#static_android.statistics.info.availableFaceDetectModes">android.<wbr/>statistics.<wbr/>info.<wbr/>available<wbr/>Face<wbr/>Detect<wbr/>Modes</a>)</li>
-<li>Optical or electrical image stabilization
-  (<a href="#static_android.lens.info.availableOpticalStabilization">android.<wbr/>lens.<wbr/>info.<wbr/>available<wbr/>Optical<wbr/>Stabilization</a>,<wbr/>
-   <a href="#static_android.control.availableVideoStabilizationModes">android.<wbr/>control.<wbr/>available<wbr/>Video<wbr/>Stabilization<wbr/>Modes</a>)</li>
-</ul>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The camera 3 HAL device can implement one of three possible operational modes; LIMITED,<wbr/>
-FULL,<wbr/> and LEVEL_<wbr/>3.<wbr/></p>
-<p>FULL support or better is expected from new higher-end devices.<wbr/> Limited
-mode has hardware requirements roughly in line with those for a camera HAL device v1
-implementation,<wbr/> and is expected from older or inexpensive devices.<wbr/> Each level is a strict
-superset of the previous level,<wbr/> and they share the same essential operational flow.<wbr/></p>
-<p>For full details refer to "S3.<wbr/> Operational Modes" in camera3.<wbr/>h</p>
-<p>Camera HAL3+ must not implement LEGACY mode.<wbr/> It is there for backwards compatibility in
-the <code>android.<wbr/>hardware.<wbr/>camera2</code> user-facing API only on HALv1 devices,<wbr/> and is implemented
-by the camera framework code.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_blackLevel" class="section">blackLevel</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.blackLevel.lock">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>black<wbr/>Level.<wbr/>lock
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether black-level compensation is locked
-to its current values,<wbr/> or is free to vary.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_HAL2">HAL2</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When set to <code>true</code> (ON),<wbr/> the values used for black-level
-compensation will not change until the lock is set to
-<code>false</code> (OFF).<wbr/></p>
-<p>Since changes to certain capture parameters (such as
-exposure time) may require resetting of black level
-compensation,<wbr/> the camera device must report whether setting
-the black level lock was successful in the output result
-metadata.<wbr/></p>
-<p>For example,<wbr/> if a sequence of requests is as follows:</p>
-<ul>
-<li>Request 1: Exposure = 10ms,<wbr/> Black level lock = OFF</li>
-<li>Request 2: Exposure = 10ms,<wbr/> Black level lock = ON</li>
-<li>Request 3: Exposure = 10ms,<wbr/> Black level lock = ON</li>
-<li>Request 4: Exposure = 20ms,<wbr/> Black level lock = ON</li>
-<li>Request 5: Exposure = 20ms,<wbr/> Black level lock = ON</li>
-<li>Request 6: Exposure = 20ms,<wbr/> Black level lock = ON</li>
-</ul>
-<p>And the exposure change in Request 4 requires the camera
-device to reset the black level offsets,<wbr/> then the output
-result metadata is expected to be:</p>
-<ul>
-<li>Result 1: Exposure = 10ms,<wbr/> Black level lock = OFF</li>
-<li>Result 2: Exposure = 10ms,<wbr/> Black level lock = ON</li>
-<li>Result 3: Exposure = 10ms,<wbr/> Black level lock = ON</li>
-<li>Result 4: Exposure = 20ms,<wbr/> Black level lock = OFF</li>
-<li>Result 5: Exposure = 20ms,<wbr/> Black level lock = ON</li>
-<li>Result 6: Exposure = 20ms,<wbr/> Black level lock = ON</li>
-</ul>
-<p>This indicates to the application that on frame 4,<wbr/> black
-levels were reset due to exposure value changes,<wbr/> and pixel
-values may not be consistent across captures.<wbr/></p>
-<p>The camera device will maintain the lock to the extent
-possible,<wbr/> only overriding the lock to OFF when changes to
-other request parameters require a black level recalculation
-or reset.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If for some reason black level locking is no longer possible
-(for example,<wbr/> the analog gain has changed,<wbr/> which forces
-black level offsets to be recalculated),<wbr/> then the HAL must
-override this request (and it must report 'OFF' when this
-does happen) until the next capture for which locking is
-possible again.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.blackLevel.lock">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>black<wbr/>Level.<wbr/>lock
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-              <span class="entry_type_hwlevel">[full] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OFF</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">ON</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Whether black-level compensation is locked
-to its current values,<wbr/> or is free to vary.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_HAL2">HAL2</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Whether the black level offset was locked for this frame.<wbr/>  Should be
-ON if <a href="#controls_android.blackLevel.lock">android.<wbr/>black<wbr/>Level.<wbr/>lock</a> was ON in the capture request,<wbr/> unless
-a change in other capture settings forced the camera device to
-perform a black level reset.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If for some reason black level locking is no longer possible
-(for example,<wbr/> the analog gain has changed,<wbr/> which forces
-black level offsets to be recalculated),<wbr/> then the HAL must
-override this request (and it must report 'OFF' when this
-does happen) until the next capture for which locking is
-possible again.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_sync" class="section">sync</td></tr>
-
-
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.sync.frameNumber">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sync.<wbr/>frame<wbr/>Number
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">int64</span>
-
-              <span class="entry_type_visibility"> [ndk_public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">CONVERGING</span>
-                    <span class="entry_type_enum_value">-1</span>
-                    <span class="entry_type_enum_notes"><p>The current result is not yet fully synchronized to any request.<wbr/></p>
-<p>Synchronization is in progress,<wbr/> and reading metadata from this
-result may include a mix of data that have taken effect since the
-last synchronization time.<wbr/></p>
-<p>In some future result,<wbr/> within <a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a> frames,<wbr/>
-this value will update to the actual frame number frame number
-the result is guaranteed to be synchronized to (as long as the
-request settings remain constant).<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">UNKNOWN</span>
-                    <span class="entry_type_enum_value">-2</span>
-                    <span class="entry_type_enum_notes"><p>The current result's synchronization status is unknown.<wbr/></p>
-<p>The result may have already converged,<wbr/> or it may be in
-progress.<wbr/>  Reading from this result may include some mix
-of settings from past requests.<wbr/></p>
-<p>After a settings change,<wbr/> the new settings will eventually all
-take effect for the output buffers and results.<wbr/> However,<wbr/> this
-value will not change when that happens.<wbr/> Altering settings
-rapidly may provide outcomes using mixes of settings from recent
-requests.<wbr/></p>
-<p>This value is intended primarily for backwards compatibility with
-the older camera implementations (for android.<wbr/>hardware.<wbr/>Camera).<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The frame number corresponding to the last request
-with which the output result (metadata + buffers) has been fully
-synchronized.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-              <p>Either a non-negative value corresponding to a
-<code>frame_<wbr/>number</code>,<wbr/> or one of the two enums (CONVERGING /<wbr/> UNKNOWN).<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>When a request is submitted to the camera device,<wbr/> there is usually a
-delay of several frames before the controls get applied.<wbr/> A camera
-device may either choose to account for this delay by implementing a
-pipeline and carefully submit well-timed atomic control updates,<wbr/> or
-it may start streaming control changes that span over several frame
-boundaries.<wbr/></p>
-<p>In the latter case,<wbr/> whenever a request's settings change relative to
-the previous submitted request,<wbr/> the full set of changes may take
-multiple frame durations to fully take effect.<wbr/> Some settings may
-take effect sooner (in less frame durations) than others.<wbr/></p>
-<p>While a set of control changes are being propagated,<wbr/> this value
-will be CONVERGING.<wbr/></p>
-<p>Once it is fully known that a set of control changes have been
-finished propagating,<wbr/> and the resulting updated control settings
-have been read back by the camera device,<wbr/> this value will be set
-to a non-negative frame number (corresponding to the request to
-which the results have synchronized to).<wbr/></p>
-<p>Older camera device implementations may not have a way to detect
-when all camera controls have been applied,<wbr/> and will always set this
-value to UNKNOWN.<wbr/></p>
-<p>FULL capability devices will always have this value set to the
-frame number of the request corresponding to this result.<wbr/></p>
-<p><em>Further details</em>:</p>
-<ul>
-<li>Whenever a request differs from the last request,<wbr/> any future
-results not yet returned may have this value set to CONVERGING (this
-could include any in-progress captures not yet returned by the camera
-device,<wbr/> for more details see pipeline considerations below).<wbr/></li>
-<li>Submitting a series of multiple requests that differ from the
-previous request (e.<wbr/>g.<wbr/> r1,<wbr/> r2,<wbr/> r3 s.<wbr/>t.<wbr/> r1 != r2 != r3)
-moves the new synchronization frame to the last non-repeating
-request (using the smallest frame number from the contiguous list of
-repeating requests).<wbr/></li>
-<li>Submitting the same request repeatedly will not change this value
-to CONVERGING,<wbr/> if it was already a non-negative value.<wbr/></li>
-<li>When this value changes to non-negative,<wbr/> that means that all of the
-metadata controls from the request have been applied,<wbr/> all of the
-metadata controls from the camera device have been read to the
-updated values (into the result),<wbr/> and all of the graphics buffers
-corresponding to this result are also synchronized to the request.<wbr/></li>
-</ul>
-<p><em>Pipeline considerations</em>:</p>
-<p>Submitting a request with updated controls relative to the previously
-submitted requests may also invalidate the synchronization state
-of all the results corresponding to currently in-flight requests.<wbr/></p>
-<p>In other words,<wbr/> results for this current request and up to
-<a href="#static_android.request.pipelineMaxDepth">android.<wbr/>request.<wbr/>pipeline<wbr/>Max<wbr/>Depth</a> prior requests may have their
-<a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> change to CONVERGING.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>Using UNKNOWN here is illegal unless <a href="#static_android.sync.maxLatency">android.<wbr/>sync.<wbr/>max<wbr/>Latency</a>
-is also UNKNOWN.<wbr/></p>
-<p>FULL capability devices should simply set this value to the
-<code>frame_<wbr/>number</code> of the request this result corresponds to.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.sync.maxLatency">
-            <td class="entry_name
-             " rowspan="5">
-              android.<wbr/>sync.<wbr/>max<wbr/>Latency
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">int32</span>
-
-              <span class="entry_type_visibility"> [public]</span>
-
-
-              <span class="entry_type_hwlevel">[legacy] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">PER_FRAME_CONTROL</span>
-                    <span class="entry_type_enum_value">0</span>
-                    <span class="entry_type_enum_notes"><p>Every frame has the requests immediately applied.<wbr/></p>
-<p>Changing controls over multiple requests one after another will
-produce results that have those controls applied atomically
-each frame.<wbr/></p>
-<p>All FULL capability devices will have this as their maxLatency.<wbr/></p></span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">UNKNOWN</span>
-                    <span class="entry_type_enum_value">-1</span>
-                    <span class="entry_type_enum_notes"><p>Each new frame has some subset (potentially the entire set)
-of the past requests applied to the camera settings.<wbr/></p>
-<p>By submitting a series of identical requests,<wbr/> the camera device
-will eventually have the camera settings applied,<wbr/> but it is
-unknown when that exact point will be.<wbr/></p>
-<p>All LEGACY capability devices will have this as their maxLatency.<wbr/></p></span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximum number of frames that can occur after a request
-(different than the previous) has been submitted,<wbr/> and before the
-result's state becomes synchronized.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Frame counts
-            </td>
-
-            <td class="entry_range">
-              <p>A positive value,<wbr/> PER_<wbr/>FRAME_<wbr/>CONTROL,<wbr/> or UNKNOWN.<wbr/></p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_V1">V1</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This defines the maximum distance (in number of metadata results),<wbr/>
-between the frame number of the request that has new controls to apply
-and the frame number of the result that has all the controls applied.<wbr/></p>
-<p>In other words this acts as an upper boundary for how many frames
-must occur before the camera device knows for a fact that the new
-submitted camera settings have been applied in outgoing frames.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">HAL Implementation Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>For example if maxLatency was 2,<wbr/></p>
-<pre><code>initial request = X (repeating)
-request1 = X
-request2 = Y
-request3 = Y
-request4 = Y
-
-where requestN has frameNumber N,<wbr/> and the first of the repeating
-initial request's has frameNumber F (and F &lt; 1).<wbr/>
-
-initial result = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == F }
-result1 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == F }
-result2 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == CONVERGING }
-result3 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == CONVERGING }
-result4 = X' + { <a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == 2 }
-
-where resultN has frameNumber N.<wbr/>
-</code></pre>
-<p>Since <code>result4</code> has a <code>frameNumber == 4</code> and
-<code><a href="#dynamic_android.sync.frameNumber">android.<wbr/>sync.<wbr/>frame<wbr/>Number</a> == 2</code>,<wbr/> the distance is clearly
-<code>4 - 2 = 2</code>.<wbr/></p>
-<p>Use <code>frame_<wbr/>count</code> from camera3_<wbr/>request_<wbr/>t instead of
-<a href="#controls_android.request.frameCount">android.<wbr/>request.<wbr/>frame<wbr/>Count</a> or
-<code><a href="https://developer.android.com/reference/android/hardware/camera2/CaptureResult.html#getFrameNumber">CaptureResult#getFrameNumber</a></code>.<wbr/></p>
-<p>LIMITED devices are strongly encouraged to use a non-negative
-value.<wbr/> If UNKNOWN is used here then app developers do not have a way
-to know when sensor settings have been applied.<wbr/></p>
-            </td>
-          </tr>
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_reprocess" class="section">reprocess</td></tr>
-
-
-      <tr><td colspan="6" class="kind">controls</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="controls_android.reprocess.effectiveExposureFactor">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [java_public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The amount of exposure time increase factor applied to the original output
-frame by the application processing before sending for reprocessing.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Relative exposure time increase factor.<wbr/>
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 1.<wbr/>0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is optional,<wbr/> and will be supported if the camera device supports YUV_<wbr/>REPROCESSING
-capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains YUV_<wbr/>REPROCESSING).<wbr/></p>
-<p>For some YUV reprocessing use cases,<wbr/> the application may choose to filter the original
-output frames to effectively reduce the noise to the same level as a frame that was
-captured with longer exposure time.<wbr/> To be more specific,<wbr/> assuming the original captured
-images were captured with a sensitivity of S and an exposure time of T,<wbr/> the model in
-the camera device is that the amount of noise in the image would be approximately what
-would be expected if the original capture parameters had been a sensitivity of
-S/<wbr/>effectiveExposureFactor and an exposure time of T*effectiveExposureFactor,<wbr/> rather
-than S and T respectively.<wbr/> If the captured images were processed by the application
-before being sent for reprocessing,<wbr/> then the application may have used image processing
-algorithms and/<wbr/>or multi-frame image fusion to reduce the noise in the
-application-processed images (input images).<wbr/> By using the effectiveExposureFactor
-control,<wbr/> the application can communicate to the camera device the actual noise level
-improvement in the application-processed image.<wbr/> With this information,<wbr/> the camera
-device can select appropriate noise reduction and edge enhancement parameters to avoid
-excessive noise reduction (<a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a>) and insufficient edge
-enhancement (<a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a>) being applied to the reprocessed frames.<wbr/></p>
-<p>For example,<wbr/> for multi-frame image fusion use case,<wbr/> the application may fuse
-multiple output frames together to a final frame for reprocessing.<wbr/> When N image are
-fused into 1 image for reprocessing,<wbr/> the exposure time increase factor could be up to
-square root of N (based on a simple photon shot noise model).<wbr/> The camera device will
-adjust the reprocessing noise reduction and edge enhancement parameters accordingly to
-produce the best quality images.<wbr/></p>
-<p>This is relative factor,<wbr/> 1.<wbr/>0 indicates the application hasn't processed the input
-buffer in a way that affects its effective exposure time.<wbr/></p>
-<p>This control is only effective for YUV reprocessing capture request.<wbr/> For noise
-reduction reprocessing,<wbr/> it is only effective when <code><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a> != OFF</code>.<wbr/>
-Similarly,<wbr/> for edge enhancement reprocessing,<wbr/> it is only effective when
-<code><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a> != OFF</code>.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">dynamic</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="dynamic_android.reprocess.effectiveExposureFactor">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>reprocess.<wbr/>effective<wbr/>Exposure<wbr/>Factor
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">float</span>
-
-              <span class="entry_type_visibility"> [java_public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The amount of exposure time increase factor applied to the original output
-frame by the application processing before sending for reprocessing.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Relative exposure time increase factor.<wbr/>
-            </td>
-
-            <td class="entry_range">
-              <p>&gt;= 1.<wbr/>0</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This is optional,<wbr/> and will be supported if the camera device supports YUV_<wbr/>REPROCESSING
-capability (<a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains YUV_<wbr/>REPROCESSING).<wbr/></p>
-<p>For some YUV reprocessing use cases,<wbr/> the application may choose to filter the original
-output frames to effectively reduce the noise to the same level as a frame that was
-captured with longer exposure time.<wbr/> To be more specific,<wbr/> assuming the original captured
-images were captured with a sensitivity of S and an exposure time of T,<wbr/> the model in
-the camera device is that the amount of noise in the image would be approximately what
-would be expected if the original capture parameters had been a sensitivity of
-S/<wbr/>effectiveExposureFactor and an exposure time of T*effectiveExposureFactor,<wbr/> rather
-than S and T respectively.<wbr/> If the captured images were processed by the application
-before being sent for reprocessing,<wbr/> then the application may have used image processing
-algorithms and/<wbr/>or multi-frame image fusion to reduce the noise in the
-application-processed images (input images).<wbr/> By using the effectiveExposureFactor
-control,<wbr/> the application can communicate to the camera device the actual noise level
-improvement in the application-processed image.<wbr/> With this information,<wbr/> the camera
-device can select appropriate noise reduction and edge enhancement parameters to avoid
-excessive noise reduction (<a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a>) and insufficient edge
-enhancement (<a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a>) being applied to the reprocessed frames.<wbr/></p>
-<p>For example,<wbr/> for multi-frame image fusion use case,<wbr/> the application may fuse
-multiple output frames together to a final frame for reprocessing.<wbr/> When N image are
-fused into 1 image for reprocessing,<wbr/> the exposure time increase factor could be up to
-square root of N (based on a simple photon shot noise model).<wbr/> The camera device will
-adjust the reprocessing noise reduction and edge enhancement parameters accordingly to
-produce the best quality images.<wbr/></p>
-<p>This is relative factor,<wbr/> 1.<wbr/>0 indicates the application hasn't processed the input
-buffer in a way that affects its effective exposure time.<wbr/></p>
-<p>This control is only effective for YUV reprocessing capture request.<wbr/> For noise
-reduction reprocessing,<wbr/> it is only effective when <code><a href="#controls_android.noiseReduction.mode">android.<wbr/>noise<wbr/>Reduction.<wbr/>mode</a> != OFF</code>.<wbr/>
-Similarly,<wbr/> for edge enhancement reprocessing,<wbr/> it is only effective when
-<code><a href="#controls_android.edge.mode">android.<wbr/>edge.<wbr/>mode</a> != OFF</code>.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.reprocess.maxCaptureStall">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>reprocess.<wbr/>max<wbr/>Capture<wbr/>Stall
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [java_public]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The maximal camera capture pipeline stall (in unit of frame count) introduced by a
-reprocess capture request.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              Number of frames.<wbr/>
-            </td>
-
-            <td class="entry_range">
-              <p>&lt;= 4</p>
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_REPROC">REPROC</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>The key describes the maximal interference that one reprocess (input) request
-can introduce to the camera simultaneous streaming of regular (output) capture
-requests,<wbr/> including repeating requests.<wbr/></p>
-<p>When a reprocessing capture request is submitted while a camera output repeating request
-(e.<wbr/>g.<wbr/> preview) is being served by the camera device,<wbr/> it may preempt the camera capture
-pipeline for at least one frame duration so that the camera device is unable to process
-the following capture request in time for the next sensor start of exposure boundary.<wbr/>
-When this happens,<wbr/> the application may observe a capture time gap (longer than one frame
-duration) between adjacent capture output frames,<wbr/> which usually exhibits as preview
-glitch if the repeating request output targets include a preview surface.<wbr/> This key gives
-the worst-case number of frame stall introduced by one reprocess request with any kind of
-formats/<wbr/>sizes combination.<wbr/></p>
-<p>If this key reports 0,<wbr/> it means a reprocess request doesn't introduce any glitch to the
-ongoing camera repeating request outputs,<wbr/> as if this reprocess request is never issued.<wbr/></p>
-<p>This key is supported if the camera device supports PRIVATE or YUV reprocessing (
-i.<wbr/>e.<wbr/> <a href="#static_android.request.availableCapabilities">android.<wbr/>request.<wbr/>available<wbr/>Capabilities</a> contains PRIVATE_<wbr/>REPROCESSING or
-YUV_<wbr/>REPROCESSING).<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-  <tr><td colspan="6" id="section_depth" class="section">depth</td></tr>
-
-
-      <tr><td colspan="6" class="kind">static</td></tr>
-
-      <thead class="entries_header">
-        <tr>
-          <th class="th_name">Property Name</th>
-          <th class="th_type">Type</th>
-          <th class="th_description">Description</th>
-          <th class="th_units">Units</th>
-          <th class="th_range">Range</th>
-          <th class="th_tags">Tags</th>
-        </tr>
-      </thead>
-
-      <tbody>
-
-        
-
-        
-
-        
-
-        
-
-                
-          <tr class="entry" id="static_android.depth.maxDepthSamples">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>depth.<wbr/>max<wbr/>Depth<wbr/>Samples
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int32</span>
-
-              <span class="entry_type_visibility"> [system]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Maximum number of points that a depth point cloud may contain.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If a camera device supports outputting depth range data in the form of a depth point
-cloud (<a href="https://developer.android.com/reference/android/graphics/ImageFormat.html#DEPTH_POINT_CLOUD">Image<wbr/>Format#DEPTH_<wbr/>POINT_<wbr/>CLOUD</a>),<wbr/> this is the maximum
-number of points an output buffer may contain.<wbr/></p>
-<p>Any given buffer may contain between 0 and maxDepthSamples points,<wbr/> inclusive.<wbr/>
-If output in the depth point cloud format is not supported,<wbr/> this entry will
-not be defined.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.depth.availableDepthStreamConfigurations">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stream<wbr/>Configurations
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">int32</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  n x 4
-                </span>
-              <span class="entry_type_visibility"> [ndk_public as streamConfiguration]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">OUTPUT</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">INPUT</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>The available depth dataspace stream
-configurations that this camera device supports
-(i.<wbr/>e.<wbr/> format,<wbr/> width,<wbr/> height,<wbr/> output/<wbr/>input stream).<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>These are output stream configurations for use with
-dataSpace HAL_<wbr/>DATASPACE_<wbr/>DEPTH.<wbr/> The configurations are
-listed as <code>(format,<wbr/> width,<wbr/> height,<wbr/> input?)</code> tuples.<wbr/></p>
-<p>Only devices that support depth output for at least
-the HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>Y16 dense depth map may include
-this entry.<wbr/></p>
-<p>A device that also supports the HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>BLOB
-sparse depth point cloud must report a single entry for
-the format in this list as <code>(HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>BLOB,<wbr/>
-<a href="#static_android.depth.maxDepthSamples">android.<wbr/>depth.<wbr/>max<wbr/>Depth<wbr/>Samples</a>,<wbr/> 1,<wbr/> OUTPUT)</code> in addition to
-the entries for HAL_<wbr/>PIXEL_<wbr/>FORMAT_<wbr/>Y16.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.depth.availableDepthMinFrameDurations">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Min<wbr/>Frame<wbr/>Durations
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4 x n
-                </span>
-              <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>This lists the minimum frame duration for each
-format/<wbr/>size combination for depth output formats.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>This should correspond to the frame duration when only that
-stream is active,<wbr/> with all processing (typically in android.<wbr/>*.<wbr/>mode)
-set to either OFF or FAST.<wbr/></p>
-<p>When multiple streams are used in a request,<wbr/> the minimum frame
-duration will be max(individual stream min durations).<wbr/></p>
-<p>The minimum frame duration of a stream (of a particular format,<wbr/> size)
-is the same regardless of whether the stream is input or output.<wbr/></p>
-<p>See <a href="#controls_android.sensor.frameDuration">android.<wbr/>sensor.<wbr/>frame<wbr/>Duration</a> and
-<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a> for more details about
-calculating the max frame rate.<wbr/></p>
-<p>(Keep in sync with <a href="https://developer.android.com/reference/android/hardware/camera2/params/StreamConfigurationMap.html#getOutputMinFrameDuration">StreamConfigurationMap#getOutputMinFrameDuration</a>)</p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.depth.availableDepthStallDurations">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>depth.<wbr/>available<wbr/>Depth<wbr/>Stall<wbr/>Durations
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name">int64</span>
-                <span class="entry_type_container">x</span>
-
-                <span class="entry_type_array">
-                  4 x n
-                </span>
-              <span class="entry_type_visibility"> [ndk_public as streamConfigurationDuration]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>This lists the maximum stall duration for each
-output format/<wbr/>size combination for depth streams.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-              (format,<wbr/> width,<wbr/> height,<wbr/> ns) x n
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-              <ul class="entry_tags">
-                  <li><a href="#tag_DEPTH">DEPTH</a></li>
-              </ul>
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>A stall duration is how much extra time would get added
-to the normal minimum frame duration for a repeating request
-that has streams with non-zero stall.<wbr/></p>
-<p>This functions similarly to
-<a href="#static_android.scaler.availableStallDurations">android.<wbr/>scaler.<wbr/>available<wbr/>Stall<wbr/>Durations</a> for depth
-streams.<wbr/></p>
-<p>All depth output stream formats may have a nonzero stall
-duration.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-                
-          <tr class="entry" id="static_android.depth.depthIsExclusive">
-            <td class="entry_name
-             " rowspan="3">
-              android.<wbr/>depth.<wbr/>depth<wbr/>Is<wbr/>Exclusive
-            </td>
-            <td class="entry_type">
-                <span class="entry_type_name entry_type_name_enum">byte</span>
-
-              <span class="entry_type_visibility"> [public as boolean]</span>
-
-
-              <span class="entry_type_hwlevel">[limited] </span>
-
-
-
-                <ul class="entry_type_enum">
-                  <li>
-                    <span class="entry_type_enum_name">FALSE</span>
-                  </li>
-                  <li>
-                    <span class="entry_type_enum_name">TRUE</span>
-                  </li>
-                </ul>
-
-            </td> <!-- entry_type -->
-
-            <td class="entry_description">
-              <p>Indicates whether a capture request may target both a
-DEPTH16 /<wbr/> DEPTH_<wbr/>POINT_<wbr/>CLOUD output,<wbr/> and normal color outputs (such as
-YUV_<wbr/>420_<wbr/>888,<wbr/> JPEG,<wbr/> or RAW) simultaneously.<wbr/></p>
-            </td>
-
-            <td class="entry_units">
-            </td>
-
-            <td class="entry_range">
-            </td>
-
-            <td class="entry_tags">
-            </td>
-
-          </tr>
-          <tr class="entries_header">
-            <th class="th_details" colspan="5">Details</th>
-          </tr>
-          <tr class="entry_cont">
-            <td class="entry_details" colspan="5">
-              <p>If TRUE,<wbr/> including both depth and color outputs in a single
-capture request is not supported.<wbr/> An application must interleave color
-and depth requests.<wbr/>  If FALSE,<wbr/> a single request can target both types
-of output.<wbr/></p>
-<p>Typically,<wbr/> this restriction exists on camera devices that
-need to emit a specific pattern or wavelength of light to
-measure depth values,<wbr/> which causes the color image to be
-corrupted during depth measurement.<wbr/></p>
-            </td>
-          </tr>
-
-
-          <tr class="entry_spacer"><td class="entry_spacer" colspan="6"></td></tr>
-           <!-- end of entry -->
-        
-        
-
-      <!-- end of kind -->
-      </tbody>
-
-  <!-- end of section -->
-<!-- </namespace> -->
-  </table>
-
-  <div class="tags" id="tag_index">
-    <h2>Tags</h2>
-    <ul>
-      <li id="tag_BC">BC - 
-        Needed for backwards compatibility with old Java API
-    
-        <ul class="tags_entries">
-          <li><a href="#controls_android.control.aeAntibandingMode">android.control.aeAntibandingMode</a> (controls)</li>
-          <li><a href="#controls_android.control.aeExposureCompensation">android.control.aeExposureCompensation</a> (controls)</li>
-          <li><a href="#controls_android.control.aeLock">android.control.aeLock</a> (controls)</li>
-          <li><a href="#controls_android.control.aeMode">android.control.aeMode</a> (controls)</li>
-          <li><a href="#controls_android.control.aeRegions">android.control.aeRegions</a> (controls)</li>
-          <li><a href="#controls_android.control.aeTargetFpsRange">android.control.aeTargetFpsRange</a> (controls)</li>
-          <li><a href="#controls_android.control.aePrecaptureTrigger">android.control.aePrecaptureTrigger</a> (controls)</li>
-          <li><a href="#controls_android.control.afMode">android.control.afMode</a> (controls)</li>
-          <li><a href="#controls_android.control.afRegions">android.control.afRegions</a> (controls)</li>
-          <li><a href="#controls_android.control.afTrigger">android.control.afTrigger</a> (controls)</li>
-          <li><a href="#controls_android.control.awbLock">android.control.awbLock</a> (controls)</li>
-          <li><a href="#controls_android.control.awbMode">android.control.awbMode</a> (controls)</li>
-          <li><a href="#controls_android.control.awbRegions">android.control.awbRegions</a> (controls)</li>
-          <li><a href="#controls_android.control.captureIntent">android.control.captureIntent</a> (controls)</li>
-          <li><a href="#controls_android.control.effectMode">android.control.effectMode</a> (controls)</li>
-          <li><a href="#controls_android.control.mode">android.control.mode</a> (controls)</li>
-          <li><a href="#controls_android.control.sceneMode">android.control.sceneMode</a> (controls)</li>
-          <li><a href="#controls_android.control.videoStabilizationMode">android.control.videoStabilizationMode</a> (controls)</li>
-          <li><a href="#static_android.control.aeAvailableAntibandingModes">android.control.aeAvailableAntibandingModes</a> (static)</li>
-          <li><a href="#static_android.control.aeAvailableModes">android.control.aeAvailableModes</a> (static)</li>
-          <li><a href="#static_android.control.aeAvailableTargetFpsRanges">android.control.aeAvailableTargetFpsRanges</a> (static)</li>
-          <li><a href="#static_android.control.aeCompensationRange">android.control.aeCompensationRange</a> (static)</li>
-          <li><a href="#static_android.control.aeCompensationStep">android.control.aeCompensationStep</a> (static)</li>
-          <li><a href="#static_android.control.afAvailableModes">android.control.afAvailableModes</a> (static)</li>
-          <li><a href="#static_android.control.availableEffects">android.control.availableEffects</a> (static)</li>
-          <li><a href="#static_android.control.availableSceneModes">android.control.availableSceneModes</a> (static)</li>
-          <li><a href="#static_android.control.availableVideoStabilizationModes">android.control.availableVideoStabilizationModes</a> (static)</li>
-          <li><a href="#static_android.control.awbAvailableModes">android.control.awbAvailableModes</a> (static)</li>
-          <li><a href="#static_android.control.maxRegions">android.control.maxRegions</a> (static)</li>
-          <li><a href="#static_android.control.sceneModeOverrides">android.control.sceneModeOverrides</a> (static)</li>
-          <li><a href="#static_android.control.aeLockAvailable">android.control.aeLockAvailable</a> (static)</li>
-          <li><a href="#static_android.control.awbLockAvailable">android.control.awbLockAvailable</a> (static)</li>
-          <li><a href="#controls_android.flash.mode">android.flash.mode</a> (controls)</li>
-          <li><a href="#static_android.flash.info.available">android.flash.info.available</a> (static)</li>
-          <li><a href="#controls_android.jpeg.gpsCoordinates">android.jpeg.gpsCoordinates</a> (controls)</li>
-          <li><a href="#controls_android.jpeg.gpsProcessingMethod">android.jpeg.gpsProcessingMethod</a> (controls)</li>
-          <li><a href="#controls_android.jpeg.gpsTimestamp">android.jpeg.gpsTimestamp</a> (controls)</li>
-          <li><a href="#controls_android.jpeg.orientation">android.jpeg.orientation</a> (controls)</li>
-          <li><a href="#controls_android.jpeg.quality">android.jpeg.quality</a> (controls)</li>
-          <li><a href="#controls_android.jpeg.thumbnailQuality">android.jpeg.thumbnailQuality</a> (controls)</li>
-          <li><a href="#controls_android.jpeg.thumbnailSize">android.jpeg.thumbnailSize</a> (controls)</li>
-          <li><a href="#static_android.jpeg.availableThumbnailSizes">android.jpeg.availableThumbnailSizes</a> (static)</li>
-          <li><a href="#controls_android.lens.focusDistance">android.lens.focusDistance</a> (controls)</li>
-          <li><a href="#static_android.lens.info.availableFocalLengths">android.lens.info.availableFocalLengths</a> (static)</li>
-          <li><a href="#dynamic_android.lens.focusRange">android.lens.focusRange</a> (dynamic)</li>
-          <li><a href="#static_android.request.maxNumOutputStreams">android.request.maxNumOutputStreams</a> (static)</li>
-          <li><a href="#controls_android.scaler.cropRegion">android.scaler.cropRegion</a> (controls)</li>
-          <li><a href="#static_android.scaler.availableFormats">android.scaler.availableFormats</a> (static)</li>
-          <li><a href="#static_android.scaler.availableJpegMinDurations">android.scaler.availableJpegMinDurations</a> (static)</li>
-          <li><a href="#static_android.scaler.availableJpegSizes">android.scaler.availableJpegSizes</a> (static)</li>
-          <li><a href="#static_android.scaler.availableMaxDigitalZoom">android.scaler.availableMaxDigitalZoom</a> (static)</li>
-          <li><a href="#static_android.scaler.availableProcessedMinDurations">android.scaler.availableProcessedMinDurations</a> (static)</li>
-          <li><a href="#static_android.scaler.availableProcessedSizes">android.scaler.availableProcessedSizes</a> (static)</li>
-          <li><a href="#static_android.scaler.availableRawMinDurations">android.scaler.availableRawMinDurations</a> (static)</li>
-          <li><a href="#static_android.sensor.info.sensitivityRange">android.sensor.info.sensitivityRange</a> (static)</li>
-          <li><a href="#static_android.sensor.info.physicalSize">android.sensor.info.physicalSize</a> (static)</li>
-          <li><a href="#static_android.sensor.info.pixelArraySize">android.sensor.info.pixelArraySize</a> (static)</li>
-          <li><a href="#static_android.sensor.orientation">android.sensor.orientation</a> (static)</li>
-          <li><a href="#dynamic_android.sensor.timestamp">android.sensor.timestamp</a> (dynamic)</li>
-          <li><a href="#controls_android.statistics.faceDetectMode">android.statistics.faceDetectMode</a> (controls)</li>
-          <li><a href="#static_android.statistics.info.maxFaceCount">android.statistics.info.maxFaceCount</a> (static)</li>
-          <li><a href="#dynamic_android.statistics.faceIds">android.statistics.faceIds</a> (dynamic)</li>
-          <li><a href="#dynamic_android.statistics.faceLandmarks">android.statistics.faceLandmarks</a> (dynamic)</li>
-          <li><a href="#dynamic_android.statistics.faceRectangles">android.statistics.faceRectangles</a> (dynamic)</li>
-          <li><a href="#dynamic_android.statistics.faceScores">android.statistics.faceScores</a> (dynamic)</li>
-          <li><a href="#dynamic_android.lens.focalLength">android.lens.focalLength</a> (dynamic)</li>
-          <li><a href="#dynamic_android.lens.focusDistance">android.lens.focusDistance</a> (dynamic)</li>
-        </ul>
-      </li> <!-- tag_BC -->
-      <li id="tag_V1">V1 - 
-        New features for first camera 2 release (API1)
-    
-        <ul class="tags_entries">
-          <li><a href="#static_android.colorCorrection.availableAberrationModes">android.colorCorrection.availableAberrationModes</a> (static)</li>
-          <li><a href="#static_android.control.availableHighSpeedVideoConfigurations">android.control.availableHighSpeedVideoConfigurations</a> (static)</li>
-          <li><a href="#controls_android.edge.mode">android.edge.mode</a> (controls)</li>
-          <li><a href="#static_android.edge.availableEdgeModes">android.edge.availableEdgeModes</a> (static)</li>
-          <li><a href="#controls_android.hotPixel.mode">android.hotPixel.mode</a> (controls)</li>
-          <li><a href="#static_android.hotPixel.availableHotPixelModes">android.hotPixel.availableHotPixelModes</a> (static)</li>
-          <li><a href="#controls_android.lens.aperture">android.lens.aperture</a> (controls)</li>
-          <li><a href="#controls_android.lens.filterDensity">android.lens.filterDensity</a> (controls)</li>
-          <li><a href="#controls_android.lens.focalLength">android.lens.focalLength</a> (controls)</li>
-          <li><a href="#controls_android.lens.focusDistance">android.lens.focusDistance</a> (controls)</li>
-          <li><a href="#controls_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a> (controls)</li>
-          <li><a href="#static_android.lens.info.availableApertures">android.lens.info.availableApertures</a> (static)</li>
-          <li><a href="#static_android.lens.info.availableFilterDensities">android.lens.info.availableFilterDensities</a> (static)</li>
-          <li><a href="#static_android.lens.info.availableFocalLengths">android.lens.info.availableFocalLengths</a> (static)</li>
-          <li><a href="#static_android.lens.info.availableOpticalStabilization">android.lens.info.availableOpticalStabilization</a> (static)</li>
-          <li><a href="#static_android.lens.info.minimumFocusDistance">android.lens.info.minimumFocusDistance</a> (static)</li>
-          <li><a href="#static_android.lens.info.shadingMapSize">android.lens.info.shadingMapSize</a> (static)</li>
-          <li><a href="#static_android.lens.info.focusDistanceCalibration">android.lens.info.focusDistanceCalibration</a> (static)</li>
-          <li><a href="#dynamic_android.lens.state">android.lens.state</a> (dynamic)</li>
-          <li><a href="#controls_android.noiseReduction.mode">android.noiseReduction.mode</a> (controls)</li>
-          <li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.noiseReduction.availableNoiseReductionModes</a> (static)</li>
-          <li><a href="#controls_android.request.id">android.request.id</a> (controls)</li>
-          <li><a href="#static_android.scaler.availableMinFrameDurations">android.scaler.availableMinFrameDurations</a> (static)</li>
-          <li><a href="#static_android.scaler.availableStallDurations">android.scaler.availableStallDurations</a> (static)</li>
-          <li><a href="#controls_android.sensor.exposureTime">android.sensor.exposureTime</a> (controls)</li>
-          <li><a href="#controls_android.sensor.frameDuration">android.sensor.frameDuration</a> (controls)</li>
-          <li><a href="#controls_android.sensor.sensitivity">android.sensor.sensitivity</a> (controls)</li>
-          <li><a href="#static_android.sensor.info.sensitivityRange">android.sensor.info.sensitivityRange</a> (static)</li>
-          <li><a href="#static_android.sensor.info.exposureTimeRange">android.sensor.info.exposureTimeRange</a> (static)</li>
-          <li><a href="#static_android.sensor.info.maxFrameDuration">android.sensor.info.maxFrameDuration</a> (static)</li>
-          <li><a href="#static_android.sensor.info.physicalSize">android.sensor.info.physicalSize</a> (static)</li>
-          <li><a href="#static_android.sensor.info.timestampSource">android.sensor.info.timestampSource</a> (static)</li>
-          <li><a href="#static_android.sensor.maxAnalogSensitivity">android.sensor.maxAnalogSensitivity</a> (static)</li>
-          <li><a href="#dynamic_android.sensor.rollingShutterSkew">android.sensor.rollingShutterSkew</a> (dynamic)</li>
-          <li><a href="#controls_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a> (controls)</li>
-          <li><a href="#static_android.statistics.info.availableHotPixelMapModes">android.statistics.info.availableHotPixelMapModes</a> (static)</li>
-          <li><a href="#dynamic_android.statistics.hotPixelMap">android.statistics.hotPixelMap</a> (dynamic)</li>
-          <li><a href="#dynamic_android.sync.frameNumber">android.sync.frameNumber</a> (dynamic)</li>
-          <li><a href="#static_android.sync.maxLatency">android.sync.maxLatency</a> (static)</li>
-          <li><a href="#dynamic_android.edge.mode">android.edge.mode</a> (dynamic)</li>
-          <li><a href="#dynamic_android.hotPixel.mode">android.hotPixel.mode</a> (dynamic)</li>
-          <li><a href="#dynamic_android.lens.aperture">android.lens.aperture</a> (dynamic)</li>
-          <li><a href="#dynamic_android.lens.filterDensity">android.lens.filterDensity</a> (dynamic)</li>
-          <li><a href="#dynamic_android.lens.opticalStabilizationMode">android.lens.opticalStabilizationMode</a> (dynamic)</li>
-          <li><a href="#dynamic_android.noiseReduction.mode">android.noiseReduction.mode</a> (dynamic)</li>
-        </ul>
-      </li> <!-- tag_V1 -->
-      <li id="tag_RAW">RAW - 
-        Needed for useful RAW image processing and DNG file support
-    
-        <ul class="tags_entries">
-          <li><a href="#controls_android.hotPixel.mode">android.hotPixel.mode</a> (controls)</li>
-          <li><a href="#static_android.hotPixel.availableHotPixelModes">android.hotPixel.availableHotPixelModes</a> (static)</li>
-          <li><a href="#static_android.sensor.info.activeArraySize">android.sensor.info.activeArraySize</a> (static)</li>
-          <li><a href="#static_android.sensor.info.colorFilterArrangement">android.sensor.info.colorFilterArrangement</a> (static)</li>
-          <li><a href="#static_android.sensor.info.pixelArraySize">android.sensor.info.pixelArraySize</a> (static)</li>
-          <li><a href="#static_android.sensor.info.whiteLevel">android.sensor.info.whiteLevel</a> (static)</li>
-          <li><a href="#static_android.sensor.info.preCorrectionActiveArraySize">android.sensor.info.preCorrectionActiveArraySize</a> (static)</li>
-          <li><a href="#static_android.sensor.referenceIlluminant1">android.sensor.referenceIlluminant1</a> (static)</li>
-          <li><a href="#static_android.sensor.referenceIlluminant2">android.sensor.referenceIlluminant2</a> (static)</li>
-          <li><a href="#static_android.sensor.calibrationTransform1">android.sensor.calibrationTransform1</a> (static)</li>
-          <li><a href="#static_android.sensor.calibrationTransform2">android.sensor.calibrationTransform2</a> (static)</li>
-          <li><a href="#static_android.sensor.colorTransform1">android.sensor.colorTransform1</a> (static)</li>
-          <li><a href="#static_android.sensor.colorTransform2">android.sensor.colorTransform2</a> (static)</li>
-          <li><a href="#static_android.sensor.forwardMatrix1">android.sensor.forwardMatrix1</a> (static)</li>
-          <li><a href="#static_android.sensor.forwardMatrix2">android.sensor.forwardMatrix2</a> (static)</li>
-          <li><a href="#static_android.sensor.blackLevelPattern">android.sensor.blackLevelPattern</a> (static)</li>
-          <li><a href="#static_android.sensor.profileHueSatMapDimensions">android.sensor.profileHueSatMapDimensions</a> (static)</li>
-          <li><a href="#dynamic_android.sensor.neutralColorPoint">android.sensor.neutralColorPoint</a> (dynamic)</li>
-          <li><a href="#dynamic_android.sensor.noiseProfile">android.sensor.noiseProfile</a> (dynamic)</li>
-          <li><a href="#dynamic_android.sensor.profileHueSatMap">android.sensor.profileHueSatMap</a> (dynamic)</li>
-          <li><a href="#dynamic_android.sensor.profileToneCurve">android.sensor.profileToneCurve</a> (dynamic)</li>
-          <li><a href="#dynamic_android.sensor.greenSplit">android.sensor.greenSplit</a> (dynamic)</li>
-          <li><a href="#dynamic_android.sensor.dynamicBlackLevel">android.sensor.dynamicBlackLevel</a> (dynamic)</li>
-          <li><a href="#dynamic_android.sensor.dynamicWhiteLevel">android.sensor.dynamicWhiteLevel</a> (dynamic)</li>
-          <li><a href="#controls_android.statistics.hotPixelMapMode">android.statistics.hotPixelMapMode</a> (controls)</li>
-          <li><a href="#static_android.statistics.info.availableHotPixelMapModes">android.statistics.info.availableHotPixelMapModes</a> (static)</li>
-          <li><a href="#dynamic_android.statistics.hotPixelMap">android.statistics.hotPixelMap</a> (dynamic)</li>
-          <li><a href="#controls_android.statistics.lensShadingMapMode">android.statistics.lensShadingMapMode</a> (controls)</li>
-          <li><a href="#dynamic_android.hotPixel.mode">android.hotPixel.mode</a> (dynamic)</li>
-        </ul>
-      </li> <!-- tag_RAW -->
-      <li id="tag_HAL2">HAL2 - 
-        Entry is only used by camera device HAL 2.x
-    
-        <ul class="tags_entries">
-          <li><a href="#controls_android.request.inputStreams">android.request.inputStreams</a> (controls)</li>
-          <li><a href="#controls_android.request.outputStreams">android.request.outputStreams</a> (controls)</li>
-          <li><a href="#controls_android.request.type">android.request.type</a> (controls)</li>
-          <li><a href="#static_android.request.maxNumReprocessStreams">android.request.maxNumReprocessStreams</a> (static)</li>
-          <li><a href="#controls_android.blackLevel.lock">android.blackLevel.lock</a> (controls)</li>
-        </ul>
-      </li> <!-- tag_HAL2 -->
-      <li id="tag_FULL">FULL - 
-        Entry is required for full hardware level devices, and optional for other hardware levels
-    
-        <ul class="tags_entries">
-          <li><a href="#static_android.sensor.maxAnalogSensitivity">android.sensor.maxAnalogSensitivity</a> (static)</li>
-        </ul>
-      </li> <!-- tag_FULL -->
-      <li id="tag_DEPTH">DEPTH - 
-        Entry is required for the depth capability.
-    
-        <ul class="tags_entries">
-          <li><a href="#static_android.lens.poseRotation">android.lens.poseRotation</a> (static)</li>
-          <li><a href="#static_android.lens.poseTranslation">android.lens.poseTranslation</a> (static)</li>
-          <li><a href="#static_android.lens.intrinsicCalibration">android.lens.intrinsicCalibration</a> (static)</li>
-          <li><a href="#static_android.lens.radialDistortion">android.lens.radialDistortion</a> (static)</li>
-          <li><a href="#static_android.depth.maxDepthSamples">android.depth.maxDepthSamples</a> (static)</li>
-          <li><a href="#static_android.depth.availableDepthStreamConfigurations">android.depth.availableDepthStreamConfigurations</a> (static)</li>
-          <li><a href="#static_android.depth.availableDepthMinFrameDurations">android.depth.availableDepthMinFrameDurations</a> (static)</li>
-          <li><a href="#static_android.depth.availableDepthStallDurations">android.depth.availableDepthStallDurations</a> (static)</li>
-        </ul>
-      </li> <!-- tag_DEPTH -->
-      <li id="tag_REPROC">REPROC - 
-        Entry is required for the YUV or PRIVATE reprocessing capability.
-    
-        <ul class="tags_entries">
-          <li><a href="#controls_android.edge.mode">android.edge.mode</a> (controls)</li>
-          <li><a href="#static_android.edge.availableEdgeModes">android.edge.availableEdgeModes</a> (static)</li>
-          <li><a href="#controls_android.noiseReduction.mode">android.noiseReduction.mode</a> (controls)</li>
-          <li><a href="#static_android.noiseReduction.availableNoiseReductionModes">android.noiseReduction.availableNoiseReductionModes</a> (static)</li>
-          <li><a href="#static_android.request.maxNumInputStreams">android.request.maxNumInputStreams</a> (static)</li>
-          <li><a href="#static_android.scaler.availableInputOutputFormatsMap">android.scaler.availableInputOutputFormatsMap</a> (static)</li>
-          <li><a href="#controls_android.reprocess.effectiveExposureFactor">android.reprocess.effectiveExposureFactor</a> (controls)</li>
-          <li><a href="#static_android.reprocess.maxCaptureStall">android.reprocess.maxCaptureStall</a> (static)</li>
-          <li><a href="#dynamic_android.edge.mode">android.edge.mode</a> (dynamic)</li>
-          <li><a href="#dynamic_android.noiseReduction.mode">android.noiseReduction.mode</a> (dynamic)</li>
-        </ul>
-      </li> <!-- tag_REPROC -->
-      <li id="tag_FUTURE">FUTURE - 
-        Entry is  under-specified and is not required for now. This is for book-keeping purpose,
-        do not implement or use it, it may be revised for future.
-    
-        <ul class="tags_entries">
-          <li><a href="#controls_android.demosaic.mode">android.demosaic.mode</a> (controls)</li>
-          <li><a href="#controls_android.edge.strength">android.edge.strength</a> (controls)</li>
-          <li><a href="#controls_android.flash.firingPower">android.flash.firingPower</a> (controls)</li>
-          <li><a href="#controls_android.flash.firingTime">android.flash.firingTime</a> (controls)</li>
-          <li><a href="#static_android.flash.info.chargeDuration">android.flash.info.chargeDuration</a> (static)</li>
-          <li><a href="#static_android.flash.colorTemperature">android.flash.colorTemperature</a> (static)</li>
-          <li><a href="#static_android.flash.maxEnergy">android.flash.maxEnergy</a> (static)</li>
-          <li><a href="#dynamic_android.jpeg.size">android.jpeg.size</a> (dynamic)</li>
-          <li><a href="#controls_android.noiseReduction.strength">android.noiseReduction.strength</a> (controls)</li>
-          <li><a href="#controls_android.request.metadataMode">android.request.metadataMode</a> (controls)</li>
-          <li><a href="#static_android.sensor.baseGainFactor">android.sensor.baseGainFactor</a> (static)</li>
-          <li><a href="#dynamic_android.sensor.temperature">android.sensor.temperature</a> (dynamic)</li>
-          <li><a href="#controls_android.shading.strength">android.shading.strength</a> (controls)</li>
-          <li><a href="#controls_android.statistics.histogramMode">android.statistics.histogramMode</a> (controls)</li>
-          <li><a href="#controls_android.statistics.sharpnessMapMode">android.statistics.sharpnessMapMode</a> (controls)</li>
-          <li><a href="#static_android.statistics.info.histogramBucketCount">android.statistics.info.histogramBucketCount</a> (static)</li>
-          <li><a href="#static_android.statistics.info.maxHistogramCount">android.statistics.info.maxHistogramCount</a> (static)</li>
-          <li><a href="#static_android.statistics.info.maxSharpnessMapValue">android.statistics.info.maxSharpnessMapValue</a> (static)</li>
-          <li><a href="#static_android.statistics.info.sharpnessMapSize">android.statistics.info.sharpnessMapSize</a> (static)</li>
-          <li><a href="#dynamic_android.statistics.histogram">android.statistics.histogram</a> (dynamic)</li>
-          <li><a href="#dynamic_android.statistics.sharpnessMap">android.statistics.sharpnessMap</a> (dynamic)</li>
-        </ul>
-      </li> <!-- tag_FUTURE -->
-    </ul>
-  </div>
-
-  [ <a href="#">top</a> ]
-
-</body>
-</html>
diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal
index 17d1d5e..67b4e44 100644
--- a/camera/metadata/3.2/types.hal
+++ b/camera/metadata/3.2/types.hal
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,17 @@
  * limitations under the License.
  */
 
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
 package android.hardware.camera.metadata@3.2;
 
 /**
  * Top level hierarchy definitions for camera metadata. *_INFO sections are for
  * the static metadata that can be retrived without opening the camera device.
- * New sections must be added right before ANDROID_SECTION_COUNT to maintain
- * existing enumerations.
  */
 enum CameraMetadataSection : uint32_t {
     ANDROID_COLOR_CORRECTION,
@@ -82,7 +86,7 @@
 };
 
 /**
- * Hierarchy positions in enum space. All vendor extension tags must be
+ * Hierarchy positions in enum space. All vendor extension sections must be
  * defined with tag >= VENDOR_SECTION_START
  */
 enum CameraMetadataSectionStart : uint32_t {
@@ -143,1175 +147,2325 @@
 };
 
 /**
- * Main enum for defining camera metadata tags. New entries must always go
- * before the section _END tag to preserve existing enumeration values. In
- * addition, the name and type of the tag needs to be added to
- * system/media/camera/src/camera_metadata_tag_info.c
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
  */
 enum CameraMetadataTag : uint32_t {
+    /** android.colorCorrection.mode [dynamic, enum, public]
+     *
+     * <p>The mode control selects how the image data is converted from the
+     * sensor's native color into linear sRGB color.</p>
+     */
     ANDROID_COLOR_CORRECTION_MODE = CameraMetadataSectionStart:ANDROID_COLOR_CORRECTION_START,
 
+    /** android.colorCorrection.transform [dynamic, rational[], public]
+     *
+     * <p>A color transform matrix to use to transform
+     * from sensor RGB color space to output linear sRGB color space.</p>
+     */
     ANDROID_COLOR_CORRECTION_TRANSFORM,
 
+    /** android.colorCorrection.gains [dynamic, float[], public]
+     *
+     * <p>Gains applying to Bayer raw color channels for
+     * white-balance.</p>
+     */
     ANDROID_COLOR_CORRECTION_GAINS,
 
+    /** android.colorCorrection.aberrationMode [dynamic, enum, public]
+     *
+     * <p>Mode of operation for the chromatic aberration correction algorithm.</p>
+     */
     ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
 
+    /** android.colorCorrection.availableAberrationModes [static, byte[], public]
+     *
+     * <p>List of aberration correction modes for ANDROID_COLOR_CORRECTION_ABERRATION_MODE that are
+     * supported by this camera device.</p>
+     *
+     * @see ANDROID_COLOR_CORRECTION_ABERRATION_MODE
+     */
     ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
 
     ANDROID_COLOR_CORRECTION_END,
 
+    /** android.control.aeAntibandingMode [dynamic, enum, public]
+     *
+     * <p>The desired setting for the camera device's auto-exposure
+     * algorithm's antibanding compensation.</p>
+     */
     ANDROID_CONTROL_AE_ANTIBANDING_MODE = CameraMetadataSectionStart:ANDROID_CONTROL_START,
 
+    /** android.control.aeExposureCompensation [dynamic, int32, public]
+     *
+     * <p>Adjustment to auto-exposure (AE) target image
+     * brightness.</p>
+     */
     ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
 
+    /** android.control.aeLock [dynamic, enum, public]
+     *
+     * <p>Whether auto-exposure (AE) is currently locked to its latest
+     * calculated values.</p>
+     */
     ANDROID_CONTROL_AE_LOCK,
 
+    /** android.control.aeMode [dynamic, enum, public]
+     *
+     * <p>The desired mode for the camera device's
+     * auto-exposure routine.</p>
+     */
     ANDROID_CONTROL_AE_MODE,
 
+    /** android.control.aeRegions [dynamic, int32[], public]
+     *
+     * <p>List of metering areas to use for auto-exposure adjustment.</p>
+     */
     ANDROID_CONTROL_AE_REGIONS,
 
+    /** android.control.aeTargetFpsRange [dynamic, int32[], public]
+     *
+     * <p>Range over which the auto-exposure routine can
+     * adjust the capture frame rate to maintain good
+     * exposure.</p>
+     */
     ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
 
+    /** android.control.aePrecaptureTrigger [dynamic, enum, public]
+     *
+     * <p>Whether the camera device will trigger a precapture
+     * metering sequence when it processes this request.</p>
+     */
     ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
 
+    /** android.control.afMode [dynamic, enum, public]
+     *
+     * <p>Whether auto-focus (AF) is currently enabled, and what
+     * mode it is set to.</p>
+     */
     ANDROID_CONTROL_AF_MODE,
 
+    /** android.control.afRegions [dynamic, int32[], public]
+     *
+     * <p>List of metering areas to use for auto-focus.</p>
+     */
     ANDROID_CONTROL_AF_REGIONS,
 
+    /** android.control.afTrigger [dynamic, enum, public]
+     *
+     * <p>Whether the camera device will trigger autofocus for this request.</p>
+     */
     ANDROID_CONTROL_AF_TRIGGER,
 
+    /** android.control.awbLock [dynamic, enum, public]
+     *
+     * <p>Whether auto-white balance (AWB) is currently locked to its
+     * latest calculated values.</p>
+     */
     ANDROID_CONTROL_AWB_LOCK,
 
+    /** android.control.awbMode [dynamic, enum, public]
+     *
+     * <p>Whether auto-white balance (AWB) is currently setting the color
+     * transform fields, and what its illumination target
+     * is.</p>
+     */
     ANDROID_CONTROL_AWB_MODE,
 
+    /** android.control.awbRegions [dynamic, int32[], public]
+     *
+     * <p>List of metering areas to use for auto-white-balance illuminant
+     * estimation.</p>
+     */
     ANDROID_CONTROL_AWB_REGIONS,
 
+    /** android.control.captureIntent [dynamic, enum, public]
+     *
+     * <p>Information to the camera device 3A (auto-exposure,
+     * auto-focus, auto-white balance) routines about the purpose
+     * of this capture, to help the camera device to decide optimal 3A
+     * strategy.</p>
+     */
     ANDROID_CONTROL_CAPTURE_INTENT,
 
+    /** android.control.effectMode [dynamic, enum, public]
+     *
+     * <p>A special color effect to apply.</p>
+     */
     ANDROID_CONTROL_EFFECT_MODE,
 
+    /** android.control.mode [dynamic, enum, public]
+     *
+     * <p>Overall mode of 3A (auto-exposure, auto-white-balance, auto-focus) control
+     * routines.</p>
+     */
     ANDROID_CONTROL_MODE,
 
+    /** android.control.sceneMode [dynamic, enum, public]
+     *
+     * <p>Control for which scene mode is currently active.</p>
+     */
     ANDROID_CONTROL_SCENE_MODE,
 
+    /** android.control.videoStabilizationMode [dynamic, enum, public]
+     *
+     * <p>Whether video stabilization is
+     * active.</p>
+     */
     ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
 
+    /** android.control.aeAvailableAntibandingModes [static, byte[], public]
+     *
+     * <p>List of auto-exposure antibanding modes for ANDROID_CONTROL_AE_ANTIBANDING_MODE that are
+     * supported by this camera device.</p>
+     *
+     * @see ANDROID_CONTROL_AE_ANTIBANDING_MODE
+     */
     ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
 
+    /** android.control.aeAvailableModes [static, byte[], public]
+     *
+     * <p>List of auto-exposure modes for ANDROID_CONTROL_AE_MODE that are supported by this camera
+     * device.</p>
+     *
+     * @see ANDROID_CONTROL_AE_MODE
+     */
     ANDROID_CONTROL_AE_AVAILABLE_MODES,
 
+    /** android.control.aeAvailableTargetFpsRanges [static, int32[], public]
+     *
+     * <p>List of frame rate ranges for ANDROID_CONTROL_AE_TARGET_FPS_RANGE supported by
+     * this camera device.</p>
+     *
+     * @see ANDROID_CONTROL_AE_TARGET_FPS_RANGE
+     */
     ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
 
+    /** android.control.aeCompensationRange [static, int32[], public]
+     *
+     * <p>Maximum and minimum exposure compensation values for
+     * ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, in counts of ANDROID_CONTROL_AE_COMPENSATION_STEP,
+     * that are supported by this camera device.</p>
+     *
+     * @see ANDROID_CONTROL_AE_COMPENSATION_STEP
+     * @see ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION
+     */
     ANDROID_CONTROL_AE_COMPENSATION_RANGE,
 
+    /** android.control.aeCompensationStep [static, rational, public]
+     *
+     * <p>Smallest step by which the exposure compensation
+     * can be changed.</p>
+     */
     ANDROID_CONTROL_AE_COMPENSATION_STEP,
 
+    /** android.control.afAvailableModes [static, byte[], public]
+     *
+     * <p>List of auto-focus (AF) modes for ANDROID_CONTROL_AF_MODE that are
+     * supported by this camera device.</p>
+     *
+     * @see ANDROID_CONTROL_AF_MODE
+     */
     ANDROID_CONTROL_AF_AVAILABLE_MODES,
 
+    /** android.control.availableEffects [static, byte[], public]
+     *
+     * <p>List of color effects for ANDROID_CONTROL_EFFECT_MODE that are supported by this camera
+     * device.</p>
+     *
+     * @see ANDROID_CONTROL_EFFECT_MODE
+     */
     ANDROID_CONTROL_AVAILABLE_EFFECTS,
 
+    /** android.control.availableSceneModes [static, byte[], public]
+     *
+     * <p>List of scene modes for ANDROID_CONTROL_SCENE_MODE that are supported by this camera
+     * device.</p>
+     *
+     * @see ANDROID_CONTROL_SCENE_MODE
+     */
     ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
 
+    /** android.control.availableVideoStabilizationModes [static, byte[], public]
+     *
+     * <p>List of video stabilization modes for ANDROID_CONTROL_VIDEO_STABILIZATION_MODE
+     * that are supported by this camera device.</p>
+     *
+     * @see ANDROID_CONTROL_VIDEO_STABILIZATION_MODE
+     */
     ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
 
+    /** android.control.awbAvailableModes [static, byte[], public]
+     *
+     * <p>List of auto-white-balance modes for ANDROID_CONTROL_AWB_MODE that are supported by this
+     * camera device.</p>
+     *
+     * @see ANDROID_CONTROL_AWB_MODE
+     */
     ANDROID_CONTROL_AWB_AVAILABLE_MODES,
 
+    /** android.control.maxRegions [static, int32[], ndk_public]
+     *
+     * <p>List of the maximum number of regions that can be used for metering in
+     * auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
+     * this corresponds to the the maximum number of elements in
+     * ANDROID_CONTROL_AE_REGIONS, ANDROID_CONTROL_AWB_REGIONS,
+     * and ANDROID_CONTROL_AF_REGIONS.</p>
+     *
+     * @see ANDROID_CONTROL_AE_REGIONS
+     * @see ANDROID_CONTROL_AF_REGIONS
+     * @see ANDROID_CONTROL_AWB_REGIONS
+     */
     ANDROID_CONTROL_MAX_REGIONS,
 
+    /** android.control.sceneModeOverrides [static, byte[], system]
+     *
+     * <p>Ordered list of auto-exposure, auto-white balance, and auto-focus
+     * settings to use with each available scene mode.</p>
+     */
     ANDROID_CONTROL_SCENE_MODE_OVERRIDES,
 
+    /** android.control.aePrecaptureId [dynamic, int32, system]
+     *
+     * <p>The ID sent with the latest
+     * CAMERA2_TRIGGER_PRECAPTURE_METERING call</p>
+     */
     ANDROID_CONTROL_AE_PRECAPTURE_ID,
 
+    /** android.control.aeState [dynamic, enum, public]
+     *
+     * <p>Current state of the auto-exposure (AE) algorithm.</p>
+     */
     ANDROID_CONTROL_AE_STATE,
 
+    /** android.control.afState [dynamic, enum, public]
+     *
+     * <p>Current state of auto-focus (AF) algorithm.</p>
+     */
     ANDROID_CONTROL_AF_STATE,
 
+    /** android.control.afTriggerId [dynamic, int32, system]
+     *
+     * <p>The ID sent with the latest
+     * CAMERA2_TRIGGER_AUTOFOCUS call</p>
+     */
     ANDROID_CONTROL_AF_TRIGGER_ID,
 
+    /** android.control.awbState [dynamic, enum, public]
+     *
+     * <p>Current state of auto-white balance (AWB) algorithm.</p>
+     */
     ANDROID_CONTROL_AWB_STATE,
 
+    /** android.control.availableHighSpeedVideoConfigurations [static, int32[], hidden]
+     *
+     * <p>List of available high speed video size, fps range and max batch size configurations
+     * supported by the camera device, in the format of (width, height, fps_min, fps_max, batch_size_max).</p>
+     */
     ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS,
 
+    /** android.control.aeLockAvailable [static, enum, public]
+     *
+     * <p>Whether the camera device supports ANDROID_CONTROL_AE_LOCK</p>
+     *
+     * @see ANDROID_CONTROL_AE_LOCK
+     */
     ANDROID_CONTROL_AE_LOCK_AVAILABLE,
 
+    /** android.control.awbLockAvailable [static, enum, public]
+     *
+     * <p>Whether the camera device supports ANDROID_CONTROL_AWB_LOCK</p>
+     *
+     * @see ANDROID_CONTROL_AWB_LOCK
+     */
     ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
 
+    /** android.control.availableModes [static, byte[], public]
+     *
+     * <p>List of control modes for ANDROID_CONTROL_MODE that are supported by this camera
+     * device.</p>
+     *
+     * @see ANDROID_CONTROL_MODE
+     */
     ANDROID_CONTROL_AVAILABLE_MODES,
 
+    /** android.control.postRawSensitivityBoostRange [static, int32[], public]
+     *
+     * <p>Range of boosts for ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST supported
+     * by this camera device.</p>
+     *
+     * @see ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST
+     */
     ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE,
 
+    /** android.control.postRawSensitivityBoost [dynamic, int32, public]
+     *
+     * <p>The amount of additional sensitivity boost applied to output images
+     * after RAW sensor data is captured.</p>
+     */
     ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST,
 
+    /** android.control.enableZsl [dynamic, enum, public]
+     *
+     * <p>Allow camera device to enable zero-shutter-lag mode for requests with
+     * ANDROID_CONTROL_CAPTURE_INTENT == STILL_CAPTURE.</p>
+     *
+     * @see ANDROID_CONTROL_CAPTURE_INTENT
+     */
     ANDROID_CONTROL_ENABLE_ZSL,
 
     ANDROID_CONTROL_END,
 
+    /** android.demosaic.mode [controls, enum, system]
+     *
+     * <p>Controls the quality of the demosaicing
+     * processing.</p>
+     */
     ANDROID_DEMOSAIC_MODE = CameraMetadataSectionStart:ANDROID_DEMOSAIC_START,
 
     ANDROID_DEMOSAIC_END,
 
+    /** android.edge.mode [dynamic, enum, public]
+     *
+     * <p>Operation mode for edge
+     * enhancement.</p>
+     */
     ANDROID_EDGE_MODE = CameraMetadataSectionStart:ANDROID_EDGE_START,
 
+    /** android.edge.strength [controls, byte, system]
+     *
+     * <p>Control the amount of edge enhancement
+     * applied to the images</p>
+     */
     ANDROID_EDGE_STRENGTH,
 
+    /** android.edge.availableEdgeModes [static, byte[], public]
+     *
+     * <p>List of edge enhancement modes for ANDROID_EDGE_MODE that are supported by this camera
+     * device.</p>
+     *
+     * @see ANDROID_EDGE_MODE
+     */
     ANDROID_EDGE_AVAILABLE_EDGE_MODES,
 
     ANDROID_EDGE_END,
 
+    /** android.flash.firingPower [dynamic, byte, system]
+     *
+     * <p>Power for flash firing/torch</p>
+     */
     ANDROID_FLASH_FIRING_POWER = CameraMetadataSectionStart:ANDROID_FLASH_START,
 
+    /** android.flash.firingTime [dynamic, int64, system]
+     *
+     * <p>Firing time of flash relative to start of
+     * exposure</p>
+     */
     ANDROID_FLASH_FIRING_TIME,
 
+    /** android.flash.mode [dynamic, enum, public]
+     *
+     * <p>The desired mode for for the camera device's flash control.</p>
+     */
     ANDROID_FLASH_MODE,
 
+    /** android.flash.colorTemperature [static, byte, system]
+     *
+     * <p>The x,y whitepoint of the
+     * flash</p>
+     */
     ANDROID_FLASH_COLOR_TEMPERATURE,
 
+    /** android.flash.maxEnergy [static, byte, system]
+     *
+     * <p>Max energy output of the flash for a full
+     * power single flash</p>
+     */
     ANDROID_FLASH_MAX_ENERGY,
 
+    /** android.flash.state [dynamic, enum, public]
+     *
+     * <p>Current state of the flash
+     * unit.</p>
+     */
     ANDROID_FLASH_STATE,
 
     ANDROID_FLASH_END,
 
+    /** android.flash.info.available [static, enum, public]
+     *
+     * <p>Whether this camera device has a
+     * flash unit.</p>
+     */
     ANDROID_FLASH_INFO_AVAILABLE = CameraMetadataSectionStart:ANDROID_FLASH_INFO_START,
 
+    /** android.flash.info.chargeDuration [static, int64, system]
+     *
+     * <p>Time taken before flash can fire
+     * again</p>
+     */
     ANDROID_FLASH_INFO_CHARGE_DURATION,
 
     ANDROID_FLASH_INFO_END,
 
+    /** android.hotPixel.mode [dynamic, enum, public]
+     *
+     * <p>Operational mode for hot pixel correction.</p>
+     */
     ANDROID_HOT_PIXEL_MODE = CameraMetadataSectionStart:ANDROID_HOT_PIXEL_START,
 
+    /** android.hotPixel.availableHotPixelModes [static, byte[], public]
+     *
+     * <p>List of hot pixel correction modes for ANDROID_HOT_PIXEL_MODE that are supported by this
+     * camera device.</p>
+     *
+     * @see ANDROID_HOT_PIXEL_MODE
+     */
     ANDROID_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES,
 
     ANDROID_HOT_PIXEL_END,
 
+    /** android.jpeg.gpsCoordinates [dynamic, double[], ndk_public]
+     *
+     * <p>GPS coordinates to include in output JPEG
+     * EXIF.</p>
+     */
     ANDROID_JPEG_GPS_COORDINATES = CameraMetadataSectionStart:ANDROID_JPEG_START,
 
+    /** android.jpeg.gpsProcessingMethod [dynamic, byte, ndk_public]
+     *
+     * <p>32 characters describing GPS algorithm to
+     * include in EXIF.</p>
+     */
     ANDROID_JPEG_GPS_PROCESSING_METHOD,
 
+    /** android.jpeg.gpsTimestamp [dynamic, int64, ndk_public]
+     *
+     * <p>Time GPS fix was made to include in
+     * EXIF.</p>
+     */
     ANDROID_JPEG_GPS_TIMESTAMP,
 
+    /** android.jpeg.orientation [dynamic, int32, public]
+     *
+     * <p>The orientation for a JPEG image.</p>
+     */
     ANDROID_JPEG_ORIENTATION,
 
+    /** android.jpeg.quality [dynamic, byte, public]
+     *
+     * <p>Compression quality of the final JPEG
+     * image.</p>
+     */
     ANDROID_JPEG_QUALITY,
 
+    /** android.jpeg.thumbnailQuality [dynamic, byte, public]
+     *
+     * <p>Compression quality of JPEG
+     * thumbnail.</p>
+     */
     ANDROID_JPEG_THUMBNAIL_QUALITY,
 
+    /** android.jpeg.thumbnailSize [dynamic, int32[], public]
+     *
+     * <p>Resolution of embedded JPEG thumbnail.</p>
+     */
     ANDROID_JPEG_THUMBNAIL_SIZE,
 
+    /** android.jpeg.availableThumbnailSizes [static, int32[], public]
+     *
+     * <p>List of JPEG thumbnail sizes for ANDROID_JPEG_THUMBNAIL_SIZE supported by this
+     * camera device.</p>
+     *
+     * @see ANDROID_JPEG_THUMBNAIL_SIZE
+     */
     ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
 
+    /** android.jpeg.maxSize [static, int32, system]
+     *
+     * <p>Maximum size in bytes for the compressed
+     * JPEG buffer</p>
+     */
     ANDROID_JPEG_MAX_SIZE,
 
+    /** android.jpeg.size [dynamic, int32, system]
+     *
+     * <p>The size of the compressed JPEG image, in
+     * bytes</p>
+     */
     ANDROID_JPEG_SIZE,
 
     ANDROID_JPEG_END,
 
+    /** android.lens.aperture [dynamic, float, public]
+     *
+     * <p>The desired lens aperture size, as a ratio of lens focal length to the
+     * effective aperture diameter.</p>
+     */
     ANDROID_LENS_APERTURE = CameraMetadataSectionStart:ANDROID_LENS_START,
 
+    /** android.lens.filterDensity [dynamic, float, public]
+     *
+     * <p>The desired setting for the lens neutral density filter(s).</p>
+     */
     ANDROID_LENS_FILTER_DENSITY,
 
+    /** android.lens.focalLength [dynamic, float, public]
+     *
+     * <p>The desired lens focal length; used for optical zoom.</p>
+     */
     ANDROID_LENS_FOCAL_LENGTH,
 
+    /** android.lens.focusDistance [dynamic, float, public]
+     *
+     * <p>Desired distance to plane of sharpest focus,
+     * measured from frontmost surface of the lens.</p>
+     */
     ANDROID_LENS_FOCUS_DISTANCE,
 
+    /** android.lens.opticalStabilizationMode [dynamic, enum, public]
+     *
+     * <p>Sets whether the camera device uses optical image stabilization (OIS)
+     * when capturing images.</p>
+     */
     ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
 
+    /** android.lens.facing [static, enum, public]
+     *
+     * <p>Direction the camera faces relative to
+     * device screen.</p>
+     */
     ANDROID_LENS_FACING,
 
+    /** android.lens.poseRotation [dynamic, float[], public]
+     *
+     * <p>The orientation of the camera relative to the sensor
+     * coordinate system.</p>
+     */
     ANDROID_LENS_POSE_ROTATION,
 
+    /** android.lens.poseTranslation [dynamic, float[], public]
+     *
+     * <p>Position of the camera optical center.</p>
+     */
     ANDROID_LENS_POSE_TRANSLATION,
 
+    /** android.lens.focusRange [dynamic, float[], public]
+     *
+     * <p>The range of scene distances that are in
+     * sharp focus (depth of field).</p>
+     */
     ANDROID_LENS_FOCUS_RANGE,
 
+    /** android.lens.state [dynamic, enum, public]
+     *
+     * <p>Current lens status.</p>
+     */
     ANDROID_LENS_STATE,
 
+    /** android.lens.intrinsicCalibration [dynamic, float[], public]
+     *
+     * <p>The parameters for this camera device's intrinsic
+     * calibration.</p>
+     */
     ANDROID_LENS_INTRINSIC_CALIBRATION,
 
+    /** android.lens.radialDistortion [dynamic, float[], public]
+     *
+     * <p>The correction coefficients to correct for this camera device's
+     * radial and tangential lens distortion.</p>
+     */
     ANDROID_LENS_RADIAL_DISTORTION,
 
     ANDROID_LENS_END,
 
+    /** android.lens.info.availableApertures [static, float[], public]
+     *
+     * <p>List of aperture size values for ANDROID_LENS_APERTURE that are
+     * supported by this camera device.</p>
+     *
+     * @see ANDROID_LENS_APERTURE
+     */
     ANDROID_LENS_INFO_AVAILABLE_APERTURES = CameraMetadataSectionStart:ANDROID_LENS_INFO_START,
 
+    /** android.lens.info.availableFilterDensities [static, float[], public]
+     *
+     * <p>List of neutral density filter values for
+     * ANDROID_LENS_FILTER_DENSITY that are supported by this camera device.</p>
+     *
+     * @see ANDROID_LENS_FILTER_DENSITY
+     */
     ANDROID_LENS_INFO_AVAILABLE_FILTER_DENSITIES,
 
+    /** android.lens.info.availableFocalLengths [static, float[], public]
+     *
+     * <p>List of focal lengths for ANDROID_LENS_FOCAL_LENGTH that are supported by this camera
+     * device.</p>
+     *
+     * @see ANDROID_LENS_FOCAL_LENGTH
+     */
     ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
 
+    /** android.lens.info.availableOpticalStabilization [static, byte[], public]
+     *
+     * <p>List of optical image stabilization (OIS) modes for
+     * ANDROID_LENS_OPTICAL_STABILIZATION_MODE that are supported by this camera device.</p>
+     *
+     * @see ANDROID_LENS_OPTICAL_STABILIZATION_MODE
+     */
     ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
 
+    /** android.lens.info.hyperfocalDistance [static, float, public]
+     *
+     * <p>Hyperfocal distance for this lens.</p>
+     */
     ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,
 
+    /** android.lens.info.minimumFocusDistance [static, float, public]
+     *
+     * <p>Shortest distance from frontmost surface
+     * of the lens that can be brought into sharp focus.</p>
+     */
     ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
 
+    /** android.lens.info.shadingMapSize [static, int32[], ndk_public]
+     *
+     * <p>Dimensions of lens shading map.</p>
+     */
     ANDROID_LENS_INFO_SHADING_MAP_SIZE,
 
+    /** android.lens.info.focusDistanceCalibration [static, enum, public]
+     *
+     * <p>The lens focus distance calibration quality.</p>
+     */
     ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
 
     ANDROID_LENS_INFO_END,
 
+    /** android.noiseReduction.mode [dynamic, enum, public]
+     *
+     * <p>Mode of operation for the noise reduction algorithm.</p>
+     */
     ANDROID_NOISE_REDUCTION_MODE = CameraMetadataSectionStart:ANDROID_NOISE_REDUCTION_START,
 
+    /** android.noiseReduction.strength [controls, byte, system]
+     *
+     * <p>Control the amount of noise reduction
+     * applied to the images</p>
+     */
     ANDROID_NOISE_REDUCTION_STRENGTH,
 
+    /** android.noiseReduction.availableNoiseReductionModes [static, byte[], public]
+     *
+     * <p>List of noise reduction modes for ANDROID_NOISE_REDUCTION_MODE that are supported
+     * by this camera device.</p>
+     *
+     * @see ANDROID_NOISE_REDUCTION_MODE
+     */
     ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
 
     ANDROID_NOISE_REDUCTION_END,
 
+    /** android.quirks.meteringCropRegion [static, byte, system]
+     *
+     * <p>If set to 1, the camera service does not
+     * scale 'normalized' coordinates with respect to the crop
+     * region. This applies to metering input (a{e,f,wb}Region
+     * and output (face rectangles).</p>
+     */
     ANDROID_QUIRKS_METERING_CROP_REGION = CameraMetadataSectionStart:ANDROID_QUIRKS_START,
 
+    /** android.quirks.triggerAfWithAuto [static, byte, system]
+     *
+     * <p>If set to 1, then the camera service always
+     * switches to FOCUS_MODE_AUTO before issuing a AF
+     * trigger.</p>
+     */
     ANDROID_QUIRKS_TRIGGER_AF_WITH_AUTO,
 
+    /** android.quirks.useZslFormat [static, byte, system]
+     *
+     * <p>If set to 1, the camera service uses
+     * CAMERA2_PIXEL_FORMAT_ZSL instead of
+     * HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED for the zero
+     * shutter lag stream</p>
+     */
     ANDROID_QUIRKS_USE_ZSL_FORMAT,
 
+    /** android.quirks.usePartialResult [static, byte, hidden]
+     *
+     * <p>If set to 1, the HAL will always split result
+     * metadata for a single capture into multiple buffers,
+     * returned using multiple process_capture_result calls.</p>
+     */
     ANDROID_QUIRKS_USE_PARTIAL_RESULT,
 
+    /** android.quirks.partialResult [dynamic, enum, hidden]
+     *
+     * <p>Whether a result given to the framework is the
+     * final one for the capture, or only a partial that contains a
+     * subset of the full set of dynamic metadata
+     * values.</p>
+     */
     ANDROID_QUIRKS_PARTIAL_RESULT,
 
     ANDROID_QUIRKS_END,
 
+    /** android.request.frameCount [dynamic, int32, hidden]
+     *
+     * <p>A frame counter set by the framework. This value monotonically
+     * increases with every new result (that is, each new result has a unique
+     * frameCount value).</p>
+     */
     ANDROID_REQUEST_FRAME_COUNT = CameraMetadataSectionStart:ANDROID_REQUEST_START,
 
+    /** android.request.id [dynamic, int32, hidden]
+     *
+     * <p>An application-specified ID for the current
+     * request. Must be maintained unchanged in output
+     * frame</p>
+     */
     ANDROID_REQUEST_ID,
 
+    /** android.request.inputStreams [controls, int32[], system]
+     *
+     * <p>List which camera reprocess stream is used
+     * for the source of reprocessing data.</p>
+     */
     ANDROID_REQUEST_INPUT_STREAMS,
 
+    /** android.request.metadataMode [dynamic, enum, system]
+     *
+     * <p>How much metadata to produce on
+     * output</p>
+     */
     ANDROID_REQUEST_METADATA_MODE,
 
+    /** android.request.outputStreams [dynamic, int32[], system]
+     *
+     * <p>Lists which camera output streams image data
+     * from this capture must be sent to</p>
+     */
     ANDROID_REQUEST_OUTPUT_STREAMS,
 
+    /** android.request.type [controls, enum, system]
+     *
+     * <p>The type of the request; either CAPTURE or
+     * REPROCESS. For legacy HAL3, this tag is redundant.</p>
+     */
     ANDROID_REQUEST_TYPE,
 
+    /** android.request.maxNumOutputStreams [static, int32[], ndk_public]
+     *
+     * <p>The maximum numbers of different types of output streams
+     * that can be configured and used simultaneously by a camera device.</p>
+     */
     ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
 
+    /** android.request.maxNumReprocessStreams [static, int32[], system]
+     *
+     * <p>How many reprocessing streams of any type
+     * can be allocated at the same time.</p>
+     */
     ANDROID_REQUEST_MAX_NUM_REPROCESS_STREAMS,
 
+    /** android.request.maxNumInputStreams [static, int32, java_public]
+     *
+     * <p>The maximum numbers of any type of input streams
+     * that can be configured and used simultaneously by a camera device.</p>
+     */
     ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
 
+    /** android.request.pipelineDepth [dynamic, byte, public]
+     *
+     * <p>Specifies the number of pipeline stages the frame went
+     * through from when it was exposed to when the final completed result
+     * was available to the framework.</p>
+     */
     ANDROID_REQUEST_PIPELINE_DEPTH,
 
+    /** android.request.pipelineMaxDepth [static, byte, public]
+     *
+     * <p>Specifies the number of maximum pipeline stages a frame
+     * has to go through from when it's exposed to when it's available
+     * to the framework.</p>
+     */
     ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
 
+    /** android.request.partialResultCount [static, int32, public]
+     *
+     * <p>Defines how many sub-components
+     * a result will be composed of.</p>
+     */
     ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
 
+    /** android.request.availableCapabilities [static, enum[], public]
+     *
+     * <p>List of capabilities that this camera device
+     * advertises as fully supporting.</p>
+     */
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
 
+    /** android.request.availableRequestKeys [static, int32[], ndk_public]
+     *
+     * <p>A list of all keys that the camera device has available
+     * to use with {@link ACaptureRequest }.</p>
+     */
     ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,
 
+    /** android.request.availableResultKeys [static, int32[], ndk_public]
+     *
+     * <p>A list of all keys that the camera device has available to use with {@link ACameraCaptureSession_captureCallback_result }.</p>
+     */
     ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
 
+    /** android.request.availableCharacteristicsKeys [static, int32[], ndk_public]
+     *
+     * <p>A list of all keys that the camera device has available to use with {@link ACameraManager_getCameraCharacteristics }.</p>
+     */
     ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
 
     ANDROID_REQUEST_END,
 
+    /** android.scaler.cropRegion [dynamic, int32[], public]
+     *
+     * <p>The desired region of the sensor to read out for this capture.</p>
+     */
     ANDROID_SCALER_CROP_REGION = CameraMetadataSectionStart:ANDROID_SCALER_START,
 
+    /** android.scaler.availableFormats [static, enum[], hidden]
+     *
+     * <p>The list of image formats that are supported by this
+     * camera device for output streams.</p>
+     */
     ANDROID_SCALER_AVAILABLE_FORMATS,
 
+    /** android.scaler.availableJpegMinDurations [static, int64[], hidden]
+     *
+     * <p>The minimum frame duration that is supported
+     * for each resolution in ANDROID_SCALER_AVAILABLE_JPEG_SIZES.</p>
+     *
+     * @see ANDROID_SCALER_AVAILABLE_JPEG_SIZES
+     */
     ANDROID_SCALER_AVAILABLE_JPEG_MIN_DURATIONS,
 
+    /** android.scaler.availableJpegSizes [static, int32[], hidden]
+     *
+     * <p>The JPEG resolutions that are supported by this camera device.</p>
+     */
     ANDROID_SCALER_AVAILABLE_JPEG_SIZES,
 
+    /** android.scaler.availableMaxDigitalZoom [static, float, public]
+     *
+     * <p>The maximum ratio between both active area width
+     * and crop region width, and active area height and
+     * crop region height, for ANDROID_SCALER_CROP_REGION.</p>
+     *
+     * @see ANDROID_SCALER_CROP_REGION
+     */
     ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
 
+    /** android.scaler.availableProcessedMinDurations [static, int64[], hidden]
+     *
+     * <p>For each available processed output size (defined in
+     * ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES), this property lists the
+     * minimum supportable frame duration for that size.</p>
+     *
+     * @see ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES
+     */
     ANDROID_SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS,
 
+    /** android.scaler.availableProcessedSizes [static, int32[], hidden]
+     *
+     * <p>The resolutions available for use with
+     * processed output streams, such as YV12, NV12, and
+     * platform opaque YUV/RGB streams to the GPU or video
+     * encoders.</p>
+     */
     ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES,
 
+    /** android.scaler.availableRawMinDurations [static, int64[], system]
+     *
+     * <p>For each available raw output size (defined in
+     * ANDROID_SCALER_AVAILABLE_RAW_SIZES), this property lists the minimum
+     * supportable frame duration for that size.</p>
+     *
+     * @see ANDROID_SCALER_AVAILABLE_RAW_SIZES
+     */
     ANDROID_SCALER_AVAILABLE_RAW_MIN_DURATIONS,
 
+    /** android.scaler.availableRawSizes [static, int32[], system]
+     *
+     * <p>The resolutions available for use with raw
+     * sensor output streams, listed as width,
+     * height</p>
+     */
     ANDROID_SCALER_AVAILABLE_RAW_SIZES,
 
+    /** android.scaler.availableInputOutputFormatsMap [static, int32, hidden]
+     *
+     * <p>The mapping of image formats that are supported by this
+     * camera device for input streams, to their corresponding output formats.</p>
+     */
     ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP,
 
+    /** android.scaler.availableStreamConfigurations [static, enum[], ndk_public]
+     *
+     * <p>The available stream configurations that this
+     * camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     */
     ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
 
+    /** android.scaler.availableMinFrameDurations [static, int64[], ndk_public]
+     *
+     * <p>This lists the minimum frame duration for each
+     * format/size combination.</p>
+     */
     ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
 
+    /** android.scaler.availableStallDurations [static, int64[], ndk_public]
+     *
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination.</p>
+     */
     ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,
 
+    /** android.scaler.croppingType [static, enum, public]
+     *
+     * <p>The crop type that this camera device supports.</p>
+     */
     ANDROID_SCALER_CROPPING_TYPE,
 
     ANDROID_SCALER_END,
 
+    /** android.sensor.exposureTime [dynamic, int64, public]
+     *
+     * <p>Duration each pixel is exposed to
+     * light.</p>
+     */
     ANDROID_SENSOR_EXPOSURE_TIME = CameraMetadataSectionStart:ANDROID_SENSOR_START,
 
+    /** android.sensor.frameDuration [dynamic, int64, public]
+     *
+     * <p>Duration from start of frame exposure to
+     * start of next frame exposure.</p>
+     */
     ANDROID_SENSOR_FRAME_DURATION,
 
+    /** android.sensor.sensitivity [dynamic, int32, public]
+     *
+     * <p>The amount of gain applied to sensor data
+     * before processing.</p>
+     */
     ANDROID_SENSOR_SENSITIVITY,
 
+    /** android.sensor.referenceIlluminant1 [static, enum, public]
+     *
+     * <p>The standard reference illuminant used as the scene light source when
+     * calculating the ANDROID_SENSOR_COLOR_TRANSFORM1,
+     * ANDROID_SENSOR_CALIBRATION_TRANSFORM1, and
+     * ANDROID_SENSOR_FORWARD_MATRIX1 matrices.</p>
+     *
+     * @see ANDROID_SENSOR_CALIBRATION_TRANSFORM1
+     * @see ANDROID_SENSOR_COLOR_TRANSFORM1
+     * @see ANDROID_SENSOR_FORWARD_MATRIX1
+     */
     ANDROID_SENSOR_REFERENCE_ILLUMINANT1,
 
+    /** android.sensor.referenceIlluminant2 [static, byte, public]
+     *
+     * <p>The standard reference illuminant used as the scene light source when
+     * calculating the ANDROID_SENSOR_COLOR_TRANSFORM2,
+     * ANDROID_SENSOR_CALIBRATION_TRANSFORM2, and
+     * ANDROID_SENSOR_FORWARD_MATRIX2 matrices.</p>
+     *
+     * @see ANDROID_SENSOR_CALIBRATION_TRANSFORM2
+     * @see ANDROID_SENSOR_COLOR_TRANSFORM2
+     * @see ANDROID_SENSOR_FORWARD_MATRIX2
+     */
     ANDROID_SENSOR_REFERENCE_ILLUMINANT2,
 
+    /** android.sensor.calibrationTransform1 [static, rational[], public]
+     *
+     * <p>A per-device calibration transform matrix that maps from the
+     * reference sensor colorspace to the actual device sensor colorspace.</p>
+     */
     ANDROID_SENSOR_CALIBRATION_TRANSFORM1,
 
+    /** android.sensor.calibrationTransform2 [static, rational[], public]
+     *
+     * <p>A per-device calibration transform matrix that maps from the
+     * reference sensor colorspace to the actual device sensor colorspace
+     * (this is the colorspace of the raw buffer data).</p>
+     */
     ANDROID_SENSOR_CALIBRATION_TRANSFORM2,
 
+    /** android.sensor.colorTransform1 [static, rational[], public]
+     *
+     * <p>A matrix that transforms color values from CIE XYZ color space to
+     * reference sensor color space.</p>
+     */
     ANDROID_SENSOR_COLOR_TRANSFORM1,
 
+    /** android.sensor.colorTransform2 [static, rational[], public]
+     *
+     * <p>A matrix that transforms color values from CIE XYZ color space to
+     * reference sensor color space.</p>
+     */
     ANDROID_SENSOR_COLOR_TRANSFORM2,
 
+    /** android.sensor.forwardMatrix1 [static, rational[], public]
+     *
+     * <p>A matrix that transforms white balanced camera colors from the reference
+     * sensor colorspace to the CIE XYZ colorspace with a D50 whitepoint.</p>
+     */
     ANDROID_SENSOR_FORWARD_MATRIX1,
 
+    /** android.sensor.forwardMatrix2 [static, rational[], public]
+     *
+     * <p>A matrix that transforms white balanced camera colors from the reference
+     * sensor colorspace to the CIE XYZ colorspace with a D50 whitepoint.</p>
+     */
     ANDROID_SENSOR_FORWARD_MATRIX2,
 
+    /** android.sensor.baseGainFactor [static, rational, system]
+     *
+     * <p>Gain factor from electrons to raw units when
+     * ISO=100</p>
+     */
     ANDROID_SENSOR_BASE_GAIN_FACTOR,
 
+    /** android.sensor.blackLevelPattern [static, int32[], public]
+     *
+     * <p>A fixed black level offset for each of the color filter arrangement
+     * (CFA) mosaic channels.</p>
+     */
     ANDROID_SENSOR_BLACK_LEVEL_PATTERN,
 
+    /** android.sensor.maxAnalogSensitivity [static, int32, public]
+     *
+     * <p>Maximum sensitivity that is implemented
+     * purely through analog gain.</p>
+     */
     ANDROID_SENSOR_MAX_ANALOG_SENSITIVITY,
 
+    /** android.sensor.orientation [static, int32, public]
+     *
+     * <p>Clockwise angle through which the output image needs to be rotated to be
+     * upright on the device screen in its native orientation.</p>
+     */
     ANDROID_SENSOR_ORIENTATION,
 
+    /** android.sensor.profileHueSatMapDimensions [static, int32[], system]
+     *
+     * <p>The number of input samples for each dimension of
+     * ANDROID_SENSOR_PROFILE_HUE_SAT_MAP.</p>
+     *
+     * @see ANDROID_SENSOR_PROFILE_HUE_SAT_MAP
+     */
     ANDROID_SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS,
 
+    /** android.sensor.timestamp [dynamic, int64, public]
+     *
+     * <p>Time at start of exposure of first
+     * row of the image sensor active array, in nanoseconds.</p>
+     */
     ANDROID_SENSOR_TIMESTAMP,
 
+    /** android.sensor.temperature [dynamic, float, system]
+     *
+     * <p>The temperature of the sensor, sampled at the time
+     * exposure began for this frame.</p>
+     * <p>The thermal diode being queried should be inside the sensor PCB, or
+     * somewhere close to it.</p>
+     */
     ANDROID_SENSOR_TEMPERATURE,
 
+    /** android.sensor.neutralColorPoint [dynamic, rational[], public]
+     *
+     * <p>The estimated camera neutral color in the native sensor colorspace at
+     * the time of capture.</p>
+     */
     ANDROID_SENSOR_NEUTRAL_COLOR_POINT,
 
+    /** android.sensor.noiseProfile [dynamic, double[], public]
+     *
+     * <p>Noise model coefficients for each CFA mosaic channel.</p>
+     */
     ANDROID_SENSOR_NOISE_PROFILE,
 
+    /** android.sensor.profileHueSatMap [dynamic, float[], system]
+     *
+     * <p>A mapping containing a hue shift, saturation scale, and value scale
+     * for each pixel.</p>
+     */
     ANDROID_SENSOR_PROFILE_HUE_SAT_MAP,
 
+    /** android.sensor.profileToneCurve [dynamic, float[], system]
+     *
+     * <p>A list of x,y samples defining a tone-mapping curve for gamma adjustment.</p>
+     */
     ANDROID_SENSOR_PROFILE_TONE_CURVE,
 
+    /** android.sensor.greenSplit [dynamic, float, public]
+     *
+     * <p>The worst-case divergence between Bayer green channels.</p>
+     */
     ANDROID_SENSOR_GREEN_SPLIT,
 
+    /** android.sensor.testPatternData [dynamic, int32[], public]
+     *
+     * <p>A pixel <code>[R, G_even, G_odd, B]</code> that supplies the test pattern
+     * when ANDROID_SENSOR_TEST_PATTERN_MODE is SOLID_COLOR.</p>
+     *
+     * @see ANDROID_SENSOR_TEST_PATTERN_MODE
+     */
     ANDROID_SENSOR_TEST_PATTERN_DATA,
 
+    /** android.sensor.testPatternMode [dynamic, enum, public]
+     *
+     * <p>When enabled, the sensor sends a test pattern instead of
+     * doing a real exposure from the camera.</p>
+     */
     ANDROID_SENSOR_TEST_PATTERN_MODE,
 
+    /** android.sensor.availableTestPatternModes [static, int32[], public]
+     *
+     * <p>List of sensor test pattern modes for ANDROID_SENSOR_TEST_PATTERN_MODE
+     * supported by this camera device.</p>
+     *
+     * @see ANDROID_SENSOR_TEST_PATTERN_MODE
+     */
     ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,
 
+    /** android.sensor.rollingShutterSkew [dynamic, int64, public]
+     *
+     * <p>Duration between the start of first row exposure
+     * and the start of last row exposure.</p>
+     */
     ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
 
+    /** android.sensor.opticalBlackRegions [static, int32[], public]
+     *
+     * <p>List of disjoint rectangles indicating the sensor
+     * optically shielded black pixel regions.</p>
+     */
     ANDROID_SENSOR_OPTICAL_BLACK_REGIONS,
 
+    /** android.sensor.dynamicBlackLevel [dynamic, float[], public]
+     *
+     * <p>A per-frame dynamic black level offset for each of the color filter
+     * arrangement (CFA) mosaic channels.</p>
+     */
     ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL,
 
+    /** android.sensor.dynamicWhiteLevel [dynamic, int32, public]
+     *
+     * <p>Maximum raw value output by sensor for this frame.</p>
+     */
     ANDROID_SENSOR_DYNAMIC_WHITE_LEVEL,
 
+    /** android.sensor.opaqueRawSize [static, int32[], system]
+     *
+     * <p>Size in bytes for all the listed opaque RAW buffer sizes</p>
+     */
     ANDROID_SENSOR_OPAQUE_RAW_SIZE,
 
     ANDROID_SENSOR_END,
 
+    /** android.sensor.info.activeArraySize [static, int32[], public]
+     *
+     * <p>The area of the image sensor which corresponds to active pixels after any geometric
+     * distortion correction has been applied.</p>
+     */
     ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE = CameraMetadataSectionStart:ANDROID_SENSOR_INFO_START,
 
+    /** android.sensor.info.sensitivityRange [static, int32[], public]
+     *
+     * <p>Range of sensitivities for ANDROID_SENSOR_SENSITIVITY supported by this
+     * camera device.</p>
+     *
+     * @see ANDROID_SENSOR_SENSITIVITY
+     */
     ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,
 
+    /** android.sensor.info.colorFilterArrangement [static, enum, public]
+     *
+     * <p>The arrangement of color filters on sensor;
+     * represents the colors in the top-left 2x2 section of
+     * the sensor, in reading order.</p>
+     */
     ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,
 
+    /** android.sensor.info.exposureTimeRange [static, int64[], public]
+     *
+     * <p>The range of image exposure times for ANDROID_SENSOR_EXPOSURE_TIME supported
+     * by this camera device.</p>
+     *
+     * @see ANDROID_SENSOR_EXPOSURE_TIME
+     */
     ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
 
+    /** android.sensor.info.maxFrameDuration [static, int64, public]
+     *
+     * <p>The maximum possible frame duration (minimum frame rate) for
+     * ANDROID_SENSOR_FRAME_DURATION that is supported this camera device.</p>
+     *
+     * @see ANDROID_SENSOR_FRAME_DURATION
+     */
     ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
 
+    /** android.sensor.info.physicalSize [static, float[], public]
+     *
+     * <p>The physical dimensions of the full pixel
+     * array.</p>
+     */
     ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
 
+    /** android.sensor.info.pixelArraySize [static, int32[], public]
+     *
+     * <p>Dimensions of the full pixel array, possibly
+     * including black calibration pixels.</p>
+     */
     ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
 
+    /** android.sensor.info.whiteLevel [static, int32, public]
+     *
+     * <p>Maximum raw value output by sensor.</p>
+     */
     ANDROID_SENSOR_INFO_WHITE_LEVEL,
 
+    /** android.sensor.info.timestampSource [static, enum, public]
+     *
+     * <p>The time base source for sensor capture start timestamps.</p>
+     */
     ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
 
+    /** android.sensor.info.lensShadingApplied [static, enum, public]
+     *
+     * <p>Whether the RAW images output from this camera device are subject to
+     * lens shading correction.</p>
+     */
     ANDROID_SENSOR_INFO_LENS_SHADING_APPLIED,
 
+    /** android.sensor.info.preCorrectionActiveArraySize [static, int32[], public]
+     *
+     * <p>The area of the image sensor which corresponds to active pixels prior to the
+     * application of any geometric distortion correction.</p>
+     */
     ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
 
     ANDROID_SENSOR_INFO_END,
 
+    /** android.shading.mode [dynamic, enum, public]
+     *
+     * <p>Quality of lens shading correction applied
+     * to the image data.</p>
+     */
     ANDROID_SHADING_MODE = CameraMetadataSectionStart:ANDROID_SHADING_START,
 
+    /** android.shading.strength [controls, byte, system]
+     *
+     * <p>Control the amount of shading correction
+     * applied to the images</p>
+     */
     ANDROID_SHADING_STRENGTH,
 
+    /** android.shading.availableModes [static, byte[], public]
+     *
+     * <p>List of lens shading modes for ANDROID_SHADING_MODE that are supported by this camera device.</p>
+     *
+     * @see ANDROID_SHADING_MODE
+     */
     ANDROID_SHADING_AVAILABLE_MODES,
 
     ANDROID_SHADING_END,
 
+    /** android.statistics.faceDetectMode [dynamic, enum, public]
+     *
+     * <p>Operating mode for the face detector
+     * unit.</p>
+     */
     ANDROID_STATISTICS_FACE_DETECT_MODE = CameraMetadataSectionStart:ANDROID_STATISTICS_START,
 
+    /** android.statistics.histogramMode [dynamic, enum, system]
+     *
+     * <p>Operating mode for histogram
+     * generation</p>
+     */
     ANDROID_STATISTICS_HISTOGRAM_MODE,
 
+    /** android.statistics.sharpnessMapMode [dynamic, enum, system]
+     *
+     * <p>Operating mode for sharpness map
+     * generation</p>
+     */
     ANDROID_STATISTICS_SHARPNESS_MAP_MODE,
 
+    /** android.statistics.hotPixelMapMode [dynamic, enum, public]
+     *
+     * <p>Operating mode for hot pixel map generation.</p>
+     */
     ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
 
+    /** android.statistics.faceIds [dynamic, int32[], ndk_public]
+     *
+     * <p>List of unique IDs for detected faces.</p>
+     */
     ANDROID_STATISTICS_FACE_IDS,
 
+    /** android.statistics.faceLandmarks [dynamic, int32[], ndk_public]
+     *
+     * <p>List of landmarks for detected
+     * faces.</p>
+     */
     ANDROID_STATISTICS_FACE_LANDMARKS,
 
+    /** android.statistics.faceRectangles [dynamic, int32[], ndk_public]
+     *
+     * <p>List of the bounding rectangles for detected
+     * faces.</p>
+     */
     ANDROID_STATISTICS_FACE_RECTANGLES,
 
+    /** android.statistics.faceScores [dynamic, byte[], ndk_public]
+     *
+     * <p>List of the face confidence scores for
+     * detected faces</p>
+     */
     ANDROID_STATISTICS_FACE_SCORES,
 
+    /** android.statistics.histogram [dynamic, int32[], system]
+     *
+     * <p>A 3-channel histogram based on the raw
+     * sensor data</p>
+     */
     ANDROID_STATISTICS_HISTOGRAM,
 
+    /** android.statistics.sharpnessMap [dynamic, int32[], system]
+     *
+     * <p>A 3-channel sharpness map, based on the raw
+     * sensor data</p>
+     */
     ANDROID_STATISTICS_SHARPNESS_MAP,
 
+    /** android.statistics.lensShadingCorrectionMap [dynamic, byte, java_public]
+     *
+     * <p>The shading map is a low-resolution floating-point map
+     * that lists the coefficients used to correct for vignetting, for each
+     * Bayer color channel.</p>
+     */
     ANDROID_STATISTICS_LENS_SHADING_CORRECTION_MAP,
 
+    /** android.statistics.lensShadingMap [dynamic, float[], ndk_public]
+     *
+     * <p>The shading map is a low-resolution floating-point map
+     * that lists the coefficients used to correct for vignetting and color shading,
+     * for each Bayer color channel of RAW image data.</p>
+     */
     ANDROID_STATISTICS_LENS_SHADING_MAP,
 
+    /** android.statistics.predictedColorGains [dynamic, float[], hidden]
+     *
+     * <p>The best-fit color channel gains calculated
+     * by the camera device's statistics units for the current output frame.</p>
+     */
     ANDROID_STATISTICS_PREDICTED_COLOR_GAINS,
 
+    /** android.statistics.predictedColorTransform [dynamic, rational[], hidden]
+     *
+     * <p>The best-fit color transform matrix estimate
+     * calculated by the camera device's statistics units for the current
+     * output frame.</p>
+     */
     ANDROID_STATISTICS_PREDICTED_COLOR_TRANSFORM,
 
+    /** android.statistics.sceneFlicker [dynamic, enum, public]
+     *
+     * <p>The camera device estimated scene illumination lighting
+     * frequency.</p>
+     */
     ANDROID_STATISTICS_SCENE_FLICKER,
 
+    /** android.statistics.hotPixelMap [dynamic, int32[], public]
+     *
+     * <p>List of <code>(x, y)</code> coordinates of hot/defective pixels on the sensor.</p>
+     */
     ANDROID_STATISTICS_HOT_PIXEL_MAP,
 
+    /** android.statistics.lensShadingMapMode [dynamic, enum, public]
+     *
+     * <p>Whether the camera device will output the lens
+     * shading map in output result metadata.</p>
+     */
     ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
 
     ANDROID_STATISTICS_END,
 
-    ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES =
-            CameraMetadataSectionStart:ANDROID_STATISTICS_INFO_START,
+    /** android.statistics.info.availableFaceDetectModes [static, byte[], public]
+     *
+     * <p>List of face detection modes for ANDROID_STATISTICS_FACE_DETECT_MODE that are
+     * supported by this camera device.</p>
+     *
+     * @see ANDROID_STATISTICS_FACE_DETECT_MODE
+     */
+    ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES = CameraMetadataSectionStart:ANDROID_STATISTICS_INFO_START,
 
+    /** android.statistics.info.histogramBucketCount [static, int32, system]
+     *
+     * <p>Number of histogram buckets
+     * supported</p>
+     */
     ANDROID_STATISTICS_INFO_HISTOGRAM_BUCKET_COUNT,
 
+    /** android.statistics.info.maxFaceCount [static, int32, public]
+     *
+     * <p>The maximum number of simultaneously detectable
+     * faces.</p>
+     */
     ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
 
+    /** android.statistics.info.maxHistogramCount [static, int32, system]
+     *
+     * <p>Maximum value possible for a histogram
+     * bucket</p>
+     */
     ANDROID_STATISTICS_INFO_MAX_HISTOGRAM_COUNT,
 
+    /** android.statistics.info.maxSharpnessMapValue [static, int32, system]
+     *
+     * <p>Maximum value possible for a sharpness map
+     * region.</p>
+     */
     ANDROID_STATISTICS_INFO_MAX_SHARPNESS_MAP_VALUE,
 
+    /** android.statistics.info.sharpnessMapSize [static, int32[], system]
+     *
+     * <p>Dimensions of the sharpness
+     * map</p>
+     */
     ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE,
 
+    /** android.statistics.info.availableHotPixelMapModes [static, byte[], public]
+     *
+     * <p>List of hot pixel map output modes for ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE that are
+     * supported by this camera device.</p>
+     *
+     * @see ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE
+     */
     ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
 
+    /** android.statistics.info.availableLensShadingMapModes [static, byte[], public]
+     *
+     * <p>List of lens shading map output modes for ANDROID_STATISTICS_LENS_SHADING_MAP_MODE that
+     * are supported by this camera device.</p>
+     *
+     * @see ANDROID_STATISTICS_LENS_SHADING_MAP_MODE
+     */
     ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
 
     ANDROID_STATISTICS_INFO_END,
 
+    /** android.tonemap.curveBlue [dynamic, float[], ndk_public]
+     *
+     * <p>Tonemapping / contrast / gamma curve for the blue
+     * channel, to use when ANDROID_TONEMAP_MODE is
+     * CONTRAST_CURVE.</p>
+     *
+     * @see ANDROID_TONEMAP_MODE
+     */
     ANDROID_TONEMAP_CURVE_BLUE = CameraMetadataSectionStart:ANDROID_TONEMAP_START,
 
+    /** android.tonemap.curveGreen [dynamic, float[], ndk_public]
+     *
+     * <p>Tonemapping / contrast / gamma curve for the green
+     * channel, to use when ANDROID_TONEMAP_MODE is
+     * CONTRAST_CURVE.</p>
+     *
+     * @see ANDROID_TONEMAP_MODE
+     */
     ANDROID_TONEMAP_CURVE_GREEN,
 
+    /** android.tonemap.curveRed [dynamic, float[], ndk_public]
+     *
+     * <p>Tonemapping / contrast / gamma curve for the red
+     * channel, to use when ANDROID_TONEMAP_MODE is
+     * CONTRAST_CURVE.</p>
+     *
+     * @see ANDROID_TONEMAP_MODE
+     */
     ANDROID_TONEMAP_CURVE_RED,
 
+    /** android.tonemap.mode [dynamic, enum, public]
+     *
+     * <p>High-level global contrast/gamma/tonemapping control.</p>
+     */
     ANDROID_TONEMAP_MODE,
 
+    /** android.tonemap.maxCurvePoints [static, int32, public]
+     *
+     * <p>Maximum number of supported points in the
+     * tonemap curve that can be used for ANDROID_TONEMAP_CURVE.</p>
+     *
+     * @see ANDROID_TONEMAP_CURVE
+     */
     ANDROID_TONEMAP_MAX_CURVE_POINTS,
 
+    /** android.tonemap.availableToneMapModes [static, byte[], public]
+     *
+     * <p>List of tonemapping modes for ANDROID_TONEMAP_MODE that are supported by this camera
+     * device.</p>
+     *
+     * @see ANDROID_TONEMAP_MODE
+     */
     ANDROID_TONEMAP_AVAILABLE_TONE_MAP_MODES,
 
+    /** android.tonemap.gamma [dynamic, float, public]
+     *
+     * <p>Tonemapping curve to use when ANDROID_TONEMAP_MODE is
+     * GAMMA_VALUE</p>
+     *
+     * @see ANDROID_TONEMAP_MODE
+     */
     ANDROID_TONEMAP_GAMMA,
 
+    /** android.tonemap.presetCurve [dynamic, enum, public]
+     *
+     * <p>Tonemapping curve to use when ANDROID_TONEMAP_MODE is
+     * PRESET_CURVE</p>
+     *
+     * @see ANDROID_TONEMAP_MODE
+     */
     ANDROID_TONEMAP_PRESET_CURVE,
 
     ANDROID_TONEMAP_END,
 
+    /** android.led.transmit [dynamic, enum, hidden]
+     *
+     * <p>This LED is nominally used to indicate to the user
+     * that the camera is powered on and may be streaming images back to the
+     * Application Processor. In certain rare circumstances, the OS may
+     * disable this when video is processed locally and not transmitted to
+     * any untrusted applications.</p>
+     * <p>In particular, the LED <em>must</em> always be on when the data could be
+     * transmitted off the device. The LED <em>should</em> always be on whenever
+     * data is stored locally on the device.</p>
+     * <p>The LED <em>may</em> be off if a trusted application is using the data that
+     * doesn't violate the above rules.</p>
+     */
     ANDROID_LED_TRANSMIT = CameraMetadataSectionStart:ANDROID_LED_START,
 
+    /** android.led.availableLeds [static, enum[], hidden]
+     *
+     * <p>A list of camera LEDs that are available on this system.</p>
+     */
     ANDROID_LED_AVAILABLE_LEDS,
 
     ANDROID_LED_END,
 
+    /** android.info.supportedHardwareLevel [static, enum, public]
+     *
+     * <p>Generally classifies the overall set of the camera device functionality.</p>
+     */
     ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL = CameraMetadataSectionStart:ANDROID_INFO_START,
 
     ANDROID_INFO_END,
 
+    /** android.blackLevel.lock [dynamic, enum, public]
+     *
+     * <p>Whether black-level compensation is locked
+     * to its current values, or is free to vary.</p>
+     */
     ANDROID_BLACK_LEVEL_LOCK = CameraMetadataSectionStart:ANDROID_BLACK_LEVEL_START,
 
     ANDROID_BLACK_LEVEL_END,
 
+    /** android.sync.frameNumber [dynamic, enum, ndk_public]
+     *
+     * <p>The frame number corresponding to the last request
+     * with which the output result (metadata + buffers) has been fully
+     * synchronized.</p>
+     */
     ANDROID_SYNC_FRAME_NUMBER = CameraMetadataSectionStart:ANDROID_SYNC_START,
 
+    /** android.sync.maxLatency [static, enum, public]
+     *
+     * <p>The maximum number of frames that can occur after a request
+     * (different than the previous) has been submitted, and before the
+     * result's state becomes synchronized.</p>
+     */
     ANDROID_SYNC_MAX_LATENCY,
 
     ANDROID_SYNC_END,
 
+    /** android.reprocess.effectiveExposureFactor [dynamic, float, java_public]
+     *
+     * <p>The amount of exposure time increase factor applied to the original output
+     * frame by the application processing before sending for reprocessing.</p>
+     */
     ANDROID_REPROCESS_EFFECTIVE_EXPOSURE_FACTOR = CameraMetadataSectionStart:ANDROID_REPROCESS_START,
 
+    /** android.reprocess.maxCaptureStall [static, int32, java_public]
+     *
+     * <p>The maximal camera capture pipeline stall (in unit of frame count) introduced by a
+     * reprocess capture request.</p>
+     */
     ANDROID_REPROCESS_MAX_CAPTURE_STALL,
 
     ANDROID_REPROCESS_END,
 
+    /** android.depth.maxDepthSamples [static, int32, system]
+     *
+     * <p>Maximum number of points that a depth point cloud may contain.</p>
+     */
     ANDROID_DEPTH_MAX_DEPTH_SAMPLES = CameraMetadataSectionStart:ANDROID_DEPTH_START,
 
+    /** android.depth.availableDepthStreamConfigurations [static, enum[], ndk_public]
+     *
+     * <p>The available depth dataspace stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     */
     ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
 
+    /** android.depth.availableDepthMinFrameDurations [static, int64[], ndk_public]
+     *
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for depth output formats.</p>
+     */
     ANDROID_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS,
 
+    /** android.depth.availableDepthStallDurations [static, int64[], ndk_public]
+     *
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for depth streams.</p>
+     */
     ANDROID_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS,
 
+    /** android.depth.depthIsExclusive [static, enum, public]
+     *
+     * <p>Indicates whether a capture request may target both a
+     * DEPTH16 / DEPTH_POINT_CLOUD output, and normal color outputs (such as
+     * YUV_420_888, JPEG, or RAW) simultaneously.</p>
+     */
     ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE,
 
     ANDROID_DEPTH_END,
 
 };
 
-/**
+/*
  * Enumeration definitions for the various entries that need them
  */
+
+/** android.colorCorrection.mode enumeration values
+ * @see ANDROID_COLOR_CORRECTION_MODE
+ */
 enum CameraMetadataEnumAndroidColorCorrectionMode : uint32_t {
     ANDROID_COLOR_CORRECTION_MODE_TRANSFORM_MATRIX,
-
     ANDROID_COLOR_CORRECTION_MODE_FAST,
-
     ANDROID_COLOR_CORRECTION_MODE_HIGH_QUALITY,
-
 };
 
+/** android.colorCorrection.aberrationMode enumeration values
+ * @see ANDROID_COLOR_CORRECTION_ABERRATION_MODE
+ */
 enum CameraMetadataEnumAndroidColorCorrectionAberrationMode : uint32_t {
     ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF,
-
     ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST,
-
     ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY,
-
 };
 
+/** android.control.aeAntibandingMode enumeration values
+ * @see ANDROID_CONTROL_AE_ANTIBANDING_MODE
+ */
 enum CameraMetadataEnumAndroidControlAeAntibandingMode : uint32_t {
     ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,
-
     ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,
-
     ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,
-
     ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,
-
 };
 
+/** android.control.aeLock enumeration values
+ * @see ANDROID_CONTROL_AE_LOCK
+ */
 enum CameraMetadataEnumAndroidControlAeLock : uint32_t {
     ANDROID_CONTROL_AE_LOCK_OFF,
-
     ANDROID_CONTROL_AE_LOCK_ON,
-
 };
 
+/** android.control.aeMode enumeration values
+ * @see ANDROID_CONTROL_AE_MODE
+ */
 enum CameraMetadataEnumAndroidControlAeMode : uint32_t {
     ANDROID_CONTROL_AE_MODE_OFF,
-
     ANDROID_CONTROL_AE_MODE_ON,
-
     ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH,
-
     ANDROID_CONTROL_AE_MODE_ON_ALWAYS_FLASH,
-
     ANDROID_CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE,
-
 };
 
+/** android.control.aePrecaptureTrigger enumeration values
+ * @see ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER
+ */
 enum CameraMetadataEnumAndroidControlAePrecaptureTrigger : uint32_t {
     ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE,
-
     ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START,
-
     ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL,
-
 };
 
+/** android.control.afMode enumeration values
+ * @see ANDROID_CONTROL_AF_MODE
+ */
 enum CameraMetadataEnumAndroidControlAfMode : uint32_t {
     ANDROID_CONTROL_AF_MODE_OFF,
-
     ANDROID_CONTROL_AF_MODE_AUTO,
-
     ANDROID_CONTROL_AF_MODE_MACRO,
-
     ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO,
-
     ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE,
-
     ANDROID_CONTROL_AF_MODE_EDOF,
-
 };
 
+/** android.control.afTrigger enumeration values
+ * @see ANDROID_CONTROL_AF_TRIGGER
+ */
 enum CameraMetadataEnumAndroidControlAfTrigger : uint32_t {
     ANDROID_CONTROL_AF_TRIGGER_IDLE,
-
     ANDROID_CONTROL_AF_TRIGGER_START,
-
     ANDROID_CONTROL_AF_TRIGGER_CANCEL,
-
 };
 
+/** android.control.awbLock enumeration values
+ * @see ANDROID_CONTROL_AWB_LOCK
+ */
 enum CameraMetadataEnumAndroidControlAwbLock : uint32_t {
     ANDROID_CONTROL_AWB_LOCK_OFF,
-
     ANDROID_CONTROL_AWB_LOCK_ON,
-
 };
 
+/** android.control.awbMode enumeration values
+ * @see ANDROID_CONTROL_AWB_MODE
+ */
 enum CameraMetadataEnumAndroidControlAwbMode : uint32_t {
     ANDROID_CONTROL_AWB_MODE_OFF,
-
     ANDROID_CONTROL_AWB_MODE_AUTO,
-
     ANDROID_CONTROL_AWB_MODE_INCANDESCENT,
-
     ANDROID_CONTROL_AWB_MODE_FLUORESCENT,
-
     ANDROID_CONTROL_AWB_MODE_WARM_FLUORESCENT,
-
     ANDROID_CONTROL_AWB_MODE_DAYLIGHT,
-
     ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT,
-
     ANDROID_CONTROL_AWB_MODE_TWILIGHT,
-
     ANDROID_CONTROL_AWB_MODE_SHADE,
-
 };
 
+/** android.control.captureIntent enumeration values
+ * @see ANDROID_CONTROL_CAPTURE_INTENT
+ */
 enum CameraMetadataEnumAndroidControlCaptureIntent : uint32_t {
     ANDROID_CONTROL_CAPTURE_INTENT_CUSTOM,
-
     ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW,
-
     ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE,
-
     ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD,
-
     ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT,
-
     ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG,
-
     ANDROID_CONTROL_CAPTURE_INTENT_MANUAL,
-
 };
 
+/** android.control.effectMode enumeration values
+ * @see ANDROID_CONTROL_EFFECT_MODE
+ */
 enum CameraMetadataEnumAndroidControlEffectMode : uint32_t {
     ANDROID_CONTROL_EFFECT_MODE_OFF,
-
     ANDROID_CONTROL_EFFECT_MODE_MONO,
-
     ANDROID_CONTROL_EFFECT_MODE_NEGATIVE,
-
     ANDROID_CONTROL_EFFECT_MODE_SOLARIZE,
-
     ANDROID_CONTROL_EFFECT_MODE_SEPIA,
-
     ANDROID_CONTROL_EFFECT_MODE_POSTERIZE,
-
     ANDROID_CONTROL_EFFECT_MODE_WHITEBOARD,
-
     ANDROID_CONTROL_EFFECT_MODE_BLACKBOARD,
-
     ANDROID_CONTROL_EFFECT_MODE_AQUA,
-
 };
 
+/** android.control.mode enumeration values
+ * @see ANDROID_CONTROL_MODE
+ */
 enum CameraMetadataEnumAndroidControlMode : uint32_t {
     ANDROID_CONTROL_MODE_OFF,
-
     ANDROID_CONTROL_MODE_AUTO,
-
     ANDROID_CONTROL_MODE_USE_SCENE_MODE,
-
     ANDROID_CONTROL_MODE_OFF_KEEP_STATE,
-
 };
 
+/** android.control.sceneMode enumeration values
+ * @see ANDROID_CONTROL_SCENE_MODE
+ */
 enum CameraMetadataEnumAndroidControlSceneMode : uint32_t {
-    ANDROID_CONTROL_SCENE_MODE_DISABLED = 0,
-
+    ANDROID_CONTROL_SCENE_MODE_DISABLED                         = 0,
     ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY,
-
     ANDROID_CONTROL_SCENE_MODE_ACTION,
-
     ANDROID_CONTROL_SCENE_MODE_PORTRAIT,
-
     ANDROID_CONTROL_SCENE_MODE_LANDSCAPE,
-
     ANDROID_CONTROL_SCENE_MODE_NIGHT,
-
     ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT,
-
     ANDROID_CONTROL_SCENE_MODE_THEATRE,
-
     ANDROID_CONTROL_SCENE_MODE_BEACH,
-
     ANDROID_CONTROL_SCENE_MODE_SNOW,
-
     ANDROID_CONTROL_SCENE_MODE_SUNSET,
-
     ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO,
-
     ANDROID_CONTROL_SCENE_MODE_FIREWORKS,
-
     ANDROID_CONTROL_SCENE_MODE_SPORTS,
-
     ANDROID_CONTROL_SCENE_MODE_PARTY,
-
     ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT,
-
     ANDROID_CONTROL_SCENE_MODE_BARCODE,
-
     ANDROID_CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO,
-
     ANDROID_CONTROL_SCENE_MODE_HDR,
-
     ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY_LOW_LIGHT,
-
-    ANDROID_CONTROL_SCENE_MODE_DEVICE_CUSTOM_START = 100,
-
-    ANDROID_CONTROL_SCENE_MODE_DEVICE_CUSTOM_END = 127,
-
+    ANDROID_CONTROL_SCENE_MODE_DEVICE_CUSTOM_START              = 100,
+    ANDROID_CONTROL_SCENE_MODE_DEVICE_CUSTOM_END                = 127,
 };
 
+/** android.control.videoStabilizationMode enumeration values
+ * @see ANDROID_CONTROL_VIDEO_STABILIZATION_MODE
+ */
 enum CameraMetadataEnumAndroidControlVideoStabilizationMode : uint32_t {
     ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,
-
     ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_ON,
-
 };
 
+/** android.control.aeState enumeration values
+ * @see ANDROID_CONTROL_AE_STATE
+ */
 enum CameraMetadataEnumAndroidControlAeState : uint32_t {
     ANDROID_CONTROL_AE_STATE_INACTIVE,
-
     ANDROID_CONTROL_AE_STATE_SEARCHING,
-
     ANDROID_CONTROL_AE_STATE_CONVERGED,
-
     ANDROID_CONTROL_AE_STATE_LOCKED,
-
     ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED,
-
     ANDROID_CONTROL_AE_STATE_PRECAPTURE,
-
 };
 
+/** android.control.afState enumeration values
+ * @see ANDROID_CONTROL_AF_STATE
+ */
 enum CameraMetadataEnumAndroidControlAfState : uint32_t {
     ANDROID_CONTROL_AF_STATE_INACTIVE,
-
     ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN,
-
     ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED,
-
     ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN,
-
     ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED,
-
     ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED,
-
     ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED,
-
 };
 
+/** android.control.awbState enumeration values
+ * @see ANDROID_CONTROL_AWB_STATE
+ */
 enum CameraMetadataEnumAndroidControlAwbState : uint32_t {
     ANDROID_CONTROL_AWB_STATE_INACTIVE,
-
     ANDROID_CONTROL_AWB_STATE_SEARCHING,
-
     ANDROID_CONTROL_AWB_STATE_CONVERGED,
-
     ANDROID_CONTROL_AWB_STATE_LOCKED,
-
 };
 
+/** android.control.aeLockAvailable enumeration values
+ * @see ANDROID_CONTROL_AE_LOCK_AVAILABLE
+ */
 enum CameraMetadataEnumAndroidControlAeLockAvailable : uint32_t {
     ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE,
-
     ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE,
-
 };
 
+/** android.control.awbLockAvailable enumeration values
+ * @see ANDROID_CONTROL_AWB_LOCK_AVAILABLE
+ */
 enum CameraMetadataEnumAndroidControlAwbLockAvailable : uint32_t {
     ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE,
-
     ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE,
-
 };
 
+/** android.control.enableZsl enumeration values
+ * @see ANDROID_CONTROL_ENABLE_ZSL
+ */
 enum CameraMetadataEnumAndroidControlEnableZsl : uint32_t {
     ANDROID_CONTROL_ENABLE_ZSL_FALSE,
-
     ANDROID_CONTROL_ENABLE_ZSL_TRUE,
-
 };
 
+/** android.demosaic.mode enumeration values
+ * @see ANDROID_DEMOSAIC_MODE
+ */
 enum CameraMetadataEnumAndroidDemosaicMode : uint32_t {
     ANDROID_DEMOSAIC_MODE_FAST,
-
     ANDROID_DEMOSAIC_MODE_HIGH_QUALITY,
-
 };
 
+/** android.edge.mode enumeration values
+ * @see ANDROID_EDGE_MODE
+ */
 enum CameraMetadataEnumAndroidEdgeMode : uint32_t {
     ANDROID_EDGE_MODE_OFF,
-
     ANDROID_EDGE_MODE_FAST,
-
     ANDROID_EDGE_MODE_HIGH_QUALITY,
-
     ANDROID_EDGE_MODE_ZERO_SHUTTER_LAG,
-
 };
 
+/** android.flash.mode enumeration values
+ * @see ANDROID_FLASH_MODE
+ */
 enum CameraMetadataEnumAndroidFlashMode : uint32_t {
     ANDROID_FLASH_MODE_OFF,
-
     ANDROID_FLASH_MODE_SINGLE,
-
     ANDROID_FLASH_MODE_TORCH,
-
 };
 
+/** android.flash.state enumeration values
+ * @see ANDROID_FLASH_STATE
+ */
 enum CameraMetadataEnumAndroidFlashState : uint32_t {
     ANDROID_FLASH_STATE_UNAVAILABLE,
-
     ANDROID_FLASH_STATE_CHARGING,
-
     ANDROID_FLASH_STATE_READY,
-
     ANDROID_FLASH_STATE_FIRED,
-
     ANDROID_FLASH_STATE_PARTIAL,
-
 };
 
+/** android.flash.info.available enumeration values
+ * @see ANDROID_FLASH_INFO_AVAILABLE
+ */
 enum CameraMetadataEnumAndroidFlashInfoAvailable : uint32_t {
     ANDROID_FLASH_INFO_AVAILABLE_FALSE,
-
     ANDROID_FLASH_INFO_AVAILABLE_TRUE,
-
 };
 
+/** android.hotPixel.mode enumeration values
+ * @see ANDROID_HOT_PIXEL_MODE
+ */
 enum CameraMetadataEnumAndroidHotPixelMode : uint32_t {
     ANDROID_HOT_PIXEL_MODE_OFF,
-
     ANDROID_HOT_PIXEL_MODE_FAST,
-
     ANDROID_HOT_PIXEL_MODE_HIGH_QUALITY,
-
 };
 
+/** android.lens.opticalStabilizationMode enumeration values
+ * @see ANDROID_LENS_OPTICAL_STABILIZATION_MODE
+ */
 enum CameraMetadataEnumAndroidLensOpticalStabilizationMode : uint32_t {
     ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,
-
     ANDROID_LENS_OPTICAL_STABILIZATION_MODE_ON,
-
 };
 
+/** android.lens.facing enumeration values
+ * @see ANDROID_LENS_FACING
+ */
 enum CameraMetadataEnumAndroidLensFacing : uint32_t {
     ANDROID_LENS_FACING_FRONT,
-
     ANDROID_LENS_FACING_BACK,
-
     ANDROID_LENS_FACING_EXTERNAL,
-
 };
 
+/** android.lens.state enumeration values
+ * @see ANDROID_LENS_STATE
+ */
 enum CameraMetadataEnumAndroidLensState : uint32_t {
     ANDROID_LENS_STATE_STATIONARY,
-
     ANDROID_LENS_STATE_MOVING,
-
 };
 
+/** android.lens.info.focusDistanceCalibration enumeration values
+ * @see ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION
+ */
 enum CameraMetadataEnumAndroidLensInfoFocusDistanceCalibration : uint32_t {
     ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED,
-
     ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_APPROXIMATE,
-
     ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_CALIBRATED,
-
 };
 
+/** android.noiseReduction.mode enumeration values
+ * @see ANDROID_NOISE_REDUCTION_MODE
+ */
 enum CameraMetadataEnumAndroidNoiseReductionMode : uint32_t {
     ANDROID_NOISE_REDUCTION_MODE_OFF,
-
     ANDROID_NOISE_REDUCTION_MODE_FAST,
-
     ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY,
-
     ANDROID_NOISE_REDUCTION_MODE_MINIMAL,
-
     ANDROID_NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG,
-
 };
 
+/** android.quirks.partialResult enumeration values
+ * @see ANDROID_QUIRKS_PARTIAL_RESULT
+ */
 enum CameraMetadataEnumAndroidQuirksPartialResult : uint32_t {
     ANDROID_QUIRKS_PARTIAL_RESULT_FINAL,
-
     ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL,
-
 };
 
+/** android.request.metadataMode enumeration values
+ * @see ANDROID_REQUEST_METADATA_MODE
+ */
 enum CameraMetadataEnumAndroidRequestMetadataMode : uint32_t {
     ANDROID_REQUEST_METADATA_MODE_NONE,
-
     ANDROID_REQUEST_METADATA_MODE_FULL,
-
 };
 
+/** android.request.type enumeration values
+ * @see ANDROID_REQUEST_TYPE
+ */
 enum CameraMetadataEnumAndroidRequestType : uint32_t {
     ANDROID_REQUEST_TYPE_CAPTURE,
-
     ANDROID_REQUEST_TYPE_REPROCESS,
-
 };
 
+/** android.request.availableCapabilities enumeration values
+ * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
+ */
 enum CameraMetadataEnumAndroidRequestAvailableCapabilities : uint32_t {
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
-
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR,
-
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING,
-
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW,
-
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING,
-
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS,
-
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE,
-
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING,
-
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT,
-
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO,
-
 };
 
+/** android.scaler.availableFormats enumeration values
+ * @see ANDROID_SCALER_AVAILABLE_FORMATS
+ */
 enum CameraMetadataEnumAndroidScalerAvailableFormats : uint32_t {
-    ANDROID_SCALER_AVAILABLE_FORMATS_RAW16 = 0x20,
-
-    ANDROID_SCALER_AVAILABLE_FORMATS_RAW_OPAQUE = 0x24,
-
-    ANDROID_SCALER_AVAILABLE_FORMATS_YV12 = 0x32315659,
-
-    ANDROID_SCALER_AVAILABLE_FORMATS_YCrCb_420_SP = 0x11,
-
-    ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED = 0x22,
-
-    ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888 = 0x23,
-
-    ANDROID_SCALER_AVAILABLE_FORMATS_BLOB = 0x21,
-
+    ANDROID_SCALER_AVAILABLE_FORMATS_RAW16                      = 0x20,
+    ANDROID_SCALER_AVAILABLE_FORMATS_RAW_OPAQUE                 = 0x24,
+    ANDROID_SCALER_AVAILABLE_FORMATS_YV12                       = 0x32315659,
+    ANDROID_SCALER_AVAILABLE_FORMATS_YCrCb_420_SP               = 0x11,
+    ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED     = 0x22,
+    ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888              = 0x23,
+    ANDROID_SCALER_AVAILABLE_FORMATS_BLOB                       = 0x21,
 };
 
+/** android.scaler.availableStreamConfigurations enumeration values
+ * @see ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+ */
 enum CameraMetadataEnumAndroidScalerAvailableStreamConfigurations : uint32_t {
     ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
-
     ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
-
 };
 
+/** android.scaler.croppingType enumeration values
+ * @see ANDROID_SCALER_CROPPING_TYPE
+ */
 enum CameraMetadataEnumAndroidScalerCroppingType : uint32_t {
     ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY,
-
     ANDROID_SCALER_CROPPING_TYPE_FREEFORM,
-
 };
 
+/** android.sensor.referenceIlluminant1 enumeration values
+ * @see ANDROID_SENSOR_REFERENCE_ILLUMINANT1
+ */
 enum CameraMetadataEnumAndroidSensorReferenceIlluminant1 : uint32_t {
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT = 1,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FLUORESCENT = 2,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_TUNGSTEN = 3,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FLASH = 4,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FINE_WEATHER = 9,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_CLOUDY_WEATHER = 10,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_SHADE = 11,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT_FLUORESCENT = 12,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAY_WHITE_FLUORESCENT = 13,
-
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT               = 1,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FLUORESCENT            = 2,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_TUNGSTEN               = 3,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FLASH                  = 4,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_FINE_WEATHER           = 9,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_CLOUDY_WEATHER         = 10,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_SHADE                  = 11,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAYLIGHT_FLUORESCENT   = 12,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_DAY_WHITE_FLUORESCENT  = 13,
     ANDROID_SENSOR_REFERENCE_ILLUMINANT1_COOL_WHITE_FLUORESCENT = 14,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_WHITE_FLUORESCENT = 15,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_A = 17,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_B = 18,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_C = 19,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D55 = 20,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D65 = 21,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D75 = 22,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D50 = 23,
-
-    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN = 24,
-
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_WHITE_FLUORESCENT      = 15,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_A             = 17,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_B             = 18,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_STANDARD_C             = 19,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D55                    = 20,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D65                    = 21,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D75                    = 22,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_D50                    = 23,
+    ANDROID_SENSOR_REFERENCE_ILLUMINANT1_ISO_STUDIO_TUNGSTEN    = 24,
 };
 
+/** android.sensor.testPatternMode enumeration values
+ * @see ANDROID_SENSOR_TEST_PATTERN_MODE
+ */
 enum CameraMetadataEnumAndroidSensorTestPatternMode : uint32_t {
     ANDROID_SENSOR_TEST_PATTERN_MODE_OFF,
-
     ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR,
-
     ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS,
-
     ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY,
-
     ANDROID_SENSOR_TEST_PATTERN_MODE_PN9,
-
-    ANDROID_SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256,
-
+    ANDROID_SENSOR_TEST_PATTERN_MODE_CUSTOM1                    = 256,
 };
 
+/** android.sensor.info.colorFilterArrangement enumeration values
+ * @see ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
+ */
 enum CameraMetadataEnumAndroidSensorInfoColorFilterArrangement : uint32_t {
     ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB,
-
     ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG,
-
     ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG,
-
     ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR,
-
     ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB,
-
 };
 
+/** android.sensor.info.timestampSource enumeration values
+ * @see ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE
+ */
 enum CameraMetadataEnumAndroidSensorInfoTimestampSource : uint32_t {
     ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN,
-
     ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME,
-
 };
 
+/** android.sensor.info.lensShadingApplied enumeration values
+ * @see ANDROID_SENSOR_INFO_LENS_SHADING_APPLIED
+ */
 enum CameraMetadataEnumAndroidSensorInfoLensShadingApplied : uint32_t {
     ANDROID_SENSOR_INFO_LENS_SHADING_APPLIED_FALSE,
-
     ANDROID_SENSOR_INFO_LENS_SHADING_APPLIED_TRUE,
-
 };
 
+/** android.shading.mode enumeration values
+ * @see ANDROID_SHADING_MODE
+ */
 enum CameraMetadataEnumAndroidShadingMode : uint32_t {
     ANDROID_SHADING_MODE_OFF,
-
     ANDROID_SHADING_MODE_FAST,
-
     ANDROID_SHADING_MODE_HIGH_QUALITY,
-
 };
 
+/** android.statistics.faceDetectMode enumeration values
+ * @see ANDROID_STATISTICS_FACE_DETECT_MODE
+ */
 enum CameraMetadataEnumAndroidStatisticsFaceDetectMode : uint32_t {
     ANDROID_STATISTICS_FACE_DETECT_MODE_OFF,
-
     ANDROID_STATISTICS_FACE_DETECT_MODE_SIMPLE,
-
     ANDROID_STATISTICS_FACE_DETECT_MODE_FULL,
-
 };
 
+/** android.statistics.histogramMode enumeration values
+ * @see ANDROID_STATISTICS_HISTOGRAM_MODE
+ */
 enum CameraMetadataEnumAndroidStatisticsHistogramMode : uint32_t {
     ANDROID_STATISTICS_HISTOGRAM_MODE_OFF,
-
     ANDROID_STATISTICS_HISTOGRAM_MODE_ON,
-
 };
 
+/** android.statistics.sharpnessMapMode enumeration values
+ * @see ANDROID_STATISTICS_SHARPNESS_MAP_MODE
+ */
 enum CameraMetadataEnumAndroidStatisticsSharpnessMapMode : uint32_t {
     ANDROID_STATISTICS_SHARPNESS_MAP_MODE_OFF,
-
     ANDROID_STATISTICS_SHARPNESS_MAP_MODE_ON,
-
 };
 
+/** android.statistics.hotPixelMapMode enumeration values
+ * @see ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE
+ */
 enum CameraMetadataEnumAndroidStatisticsHotPixelMapMode : uint32_t {
     ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF,
-
     ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_ON,
-
 };
 
+/** android.statistics.sceneFlicker enumeration values
+ * @see ANDROID_STATISTICS_SCENE_FLICKER
+ */
 enum CameraMetadataEnumAndroidStatisticsSceneFlicker : uint32_t {
     ANDROID_STATISTICS_SCENE_FLICKER_NONE,
-
     ANDROID_STATISTICS_SCENE_FLICKER_50HZ,
-
     ANDROID_STATISTICS_SCENE_FLICKER_60HZ,
-
 };
 
+/** android.statistics.lensShadingMapMode enumeration values
+ * @see ANDROID_STATISTICS_LENS_SHADING_MAP_MODE
+ */
 enum CameraMetadataEnumAndroidStatisticsLensShadingMapMode : uint32_t {
     ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF,
-
     ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON,
-
 };
 
+/** android.tonemap.mode enumeration values
+ * @see ANDROID_TONEMAP_MODE
+ */
 enum CameraMetadataEnumAndroidTonemapMode : uint32_t {
     ANDROID_TONEMAP_MODE_CONTRAST_CURVE,
-
     ANDROID_TONEMAP_MODE_FAST,
-
     ANDROID_TONEMAP_MODE_HIGH_QUALITY,
-
     ANDROID_TONEMAP_MODE_GAMMA_VALUE,
-
     ANDROID_TONEMAP_MODE_PRESET_CURVE,
-
 };
 
+/** android.tonemap.presetCurve enumeration values
+ * @see ANDROID_TONEMAP_PRESET_CURVE
+ */
 enum CameraMetadataEnumAndroidTonemapPresetCurve : uint32_t {
     ANDROID_TONEMAP_PRESET_CURVE_SRGB,
-
     ANDROID_TONEMAP_PRESET_CURVE_REC709,
-
 };
 
+/** android.led.transmit enumeration values
+ * @see ANDROID_LED_TRANSMIT
+ */
 enum CameraMetadataEnumAndroidLedTransmit : uint32_t {
     ANDROID_LED_TRANSMIT_OFF,
-
     ANDROID_LED_TRANSMIT_ON,
-
 };
 
+/** android.led.availableLeds enumeration values
+ * @see ANDROID_LED_AVAILABLE_LEDS
+ */
 enum CameraMetadataEnumAndroidLedAvailableLeds : uint32_t {
     ANDROID_LED_AVAILABLE_LEDS_TRANSMIT,
-
 };
 
+/** android.info.supportedHardwareLevel enumeration values
+ * @see ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL
+ */
 enum CameraMetadataEnumAndroidInfoSupportedHardwareLevel : uint32_t {
     ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED,
-
     ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
-
     ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY,
-
     ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3,
-
 };
 
+/** android.blackLevel.lock enumeration values
+ * @see ANDROID_BLACK_LEVEL_LOCK
+ */
 enum CameraMetadataEnumAndroidBlackLevelLock : uint32_t {
     ANDROID_BLACK_LEVEL_LOCK_OFF,
-
     ANDROID_BLACK_LEVEL_LOCK_ON,
-
 };
 
+/** android.sync.frameNumber enumeration values
+ * @see ANDROID_SYNC_FRAME_NUMBER
+ */
 enum CameraMetadataEnumAndroidSyncFrameNumber : uint32_t {
-    ANDROID_SYNC_FRAME_NUMBER_CONVERGING = -1,
-
-    ANDROID_SYNC_FRAME_NUMBER_UNKNOWN = -2,
-
+    ANDROID_SYNC_FRAME_NUMBER_CONVERGING                        = -1,
+    ANDROID_SYNC_FRAME_NUMBER_UNKNOWN                           = -2,
 };
 
+/** android.sync.maxLatency enumeration values
+ * @see ANDROID_SYNC_MAX_LATENCY
+ */
 enum CameraMetadataEnumAndroidSyncMaxLatency : uint32_t {
-    ANDROID_SYNC_MAX_LATENCY_PER_FRAME_CONTROL = 0,
-
-    ANDROID_SYNC_MAX_LATENCY_UNKNOWN = -1,
-
+    ANDROID_SYNC_MAX_LATENCY_PER_FRAME_CONTROL                  = 0,
+    ANDROID_SYNC_MAX_LATENCY_UNKNOWN                            = -1,
 };
 
+/** android.depth.availableDepthStreamConfigurations enumeration values
+ * @see ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS
+ */
 enum CameraMetadataEnumAndroidDepthAvailableDepthStreamConfigurations : uint32_t {
     ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT,
-
     ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_INPUT,
-
 };
 
+/** android.depth.depthIsExclusive enumeration values
+ * @see ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE
+ */
 enum CameraMetadataEnumAndroidDepthDepthIsExclusive : uint32_t {
     ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_FALSE,
-
     ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE_TRUE,
-
 };
diff --git a/camera/metadata/3.3/Android.bp b/camera/metadata/3.3/Android.bp
new file mode 100644
index 0000000..166c2ac
--- /dev/null
+++ b/camera/metadata/3.3/Android.bp
@@ -0,0 +1,30 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.metadata@3.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.metadata@3.2",
+    ],
+    types: [
+        "CameraMetadataEnumAndroidControlAeMode",
+        "CameraMetadataEnumAndroidControlAfSceneChange",
+        "CameraMetadataEnumAndroidControlCaptureIntent",
+        "CameraMetadataEnumAndroidInfoSupportedHardwareLevel",
+        "CameraMetadataEnumAndroidLensPoseReference",
+        "CameraMetadataEnumAndroidLogicalMultiCameraSensorSyncType",
+        "CameraMetadataEnumAndroidRequestAvailableCapabilities",
+        "CameraMetadataEnumAndroidStatisticsOisDataMode",
+        "CameraMetadataSection",
+        "CameraMetadataSectionStart",
+        "CameraMetadataTag",
+    ],
+    gen_java: true,
+}
+
diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal
new file mode 100644
index 0000000..d2a5886
--- /dev/null
+++ b/camera/metadata/3.3/types.hal
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.3;
+
+/* Include definitions from all prior minor HAL metadata revisions */
+import android.hardware.camera.metadata@3.2;
+
+/**
+ * Top level hierarchy definitions for camera metadata. *_INFO sections are for
+ * the static metadata that can be retrived without opening the camera device.
+ */
+enum CameraMetadataSection : @3.2::CameraMetadataSection {
+    ANDROID_LOGICAL_MULTI_CAMERA =
+        android.hardware.camera.metadata@3.2::CameraMetadataSection:ANDROID_SECTION_COUNT,
+
+    ANDROID_SECTION_COUNT_3_3,
+
+    VENDOR_SECTION_3_3 = 0x8000,
+
+};
+
+/**
+ * Hierarchy positions in enum space. All vendor extension sections must be
+ * defined with tag >= VENDOR_SECTION_START
+ */
+enum CameraMetadataSectionStart : android.hardware.camera.metadata@3.2::CameraMetadataSectionStart {
+    ANDROID_LOGICAL_MULTI_CAMERA_START = CameraMetadataSection:ANDROID_LOGICAL_MULTI_CAMERA << 16,
+
+    VENDOR_SECTION_START_3_3 = CameraMetadataSection:VENDOR_SECTION_3_3 << 16,
+
+};
+
+/**
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
+ */
+enum CameraMetadataTag : @3.2::CameraMetadataTag {
+    /** android.control.afSceneChange [dynamic, enum, public]
+     *
+     * <p>Whether a significant scene change is detected within the currently-set AF
+     * region(s).</p>
+     */
+    ANDROID_CONTROL_AF_SCENE_CHANGE = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_CONTROL_END,
+
+    ANDROID_CONTROL_END_3_3,
+
+    /** android.lens.poseReference [static, enum, public]
+     *
+     * <p>The origin for ANDROID_LENS_POSE_TRANSLATION.</p>
+     *
+     * @see ANDROID_LENS_POSE_TRANSLATION
+     */
+    ANDROID_LENS_POSE_REFERENCE = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_LENS_END,
+
+    ANDROID_LENS_END_3_3,
+
+    /** android.request.availableSessionKeys [static, int32[], ndk_public]
+     *
+     * <p>A subset of the available request keys that the camera device
+     * can pass as part of the capture session initialization.</p>
+     */
+    ANDROID_REQUEST_AVAILABLE_SESSION_KEYS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_REQUEST_END,
+
+    /** android.request.availablePhysicalCameraRequestKeys [static, int32[], hidden]
+     *
+     * <p>A subset of the available request keys that can be overriden for
+     * physical devices backing a logical multi-camera.</p>
+     */
+    ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS,
+
+    ANDROID_REQUEST_END_3_3,
+
+    /** android.statistics.oisDataMode [dynamic, enum, public]
+     *
+     * <p>Whether the camera device outputs the OIS data in output
+     * result metadata.</p>
+     */
+    ANDROID_STATISTICS_OIS_DATA_MODE = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_STATISTICS_END,
+
+    /** android.statistics.oisTimestamps [dynamic, int64[], public]
+     *
+     * <p>An array of timestamps of OIS samples, in nanoseconds.</p>
+     */
+    ANDROID_STATISTICS_OIS_TIMESTAMPS,
+
+    /** android.statistics.oisXShifts [dynamic, float[], public]
+     *
+     * <p>An array of shifts of OIS samples, in x direction.</p>
+     */
+    ANDROID_STATISTICS_OIS_X_SHIFTS,
+
+    /** android.statistics.oisYShifts [dynamic, float[], public]
+     *
+     * <p>An array of shifts of OIS samples, in y direction.</p>
+     */
+    ANDROID_STATISTICS_OIS_Y_SHIFTS,
+
+    ANDROID_STATISTICS_END_3_3,
+
+    /** android.statistics.info.availableOisDataModes [static, byte[], public]
+     *
+     * <p>List of OIS data output modes for ANDROID_STATISTICS_OIS_DATA_MODE that
+     * are supported by this camera device.</p>
+     *
+     * @see ANDROID_STATISTICS_OIS_DATA_MODE
+     */
+    ANDROID_STATISTICS_INFO_AVAILABLE_OIS_DATA_MODES = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_STATISTICS_INFO_END,
+
+    ANDROID_STATISTICS_INFO_END_3_3,
+
+    /** android.info.version [static, byte, public]
+     *
+     * <p>A short string for manufacturer version information about the camera device, such as
+     * ISP hardware, sensors, etc.</p>
+     */
+    ANDROID_INFO_VERSION = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_INFO_END,
+
+    ANDROID_INFO_END_3_3,
+
+    /** android.logicalMultiCamera.physicalIds [static, byte[], hidden]
+     *
+     * <p>String containing the ids of the underlying physical cameras.</p>
+     */
+    ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS = CameraMetadataSectionStart:ANDROID_LOGICAL_MULTI_CAMERA_START,
+
+    /** android.logicalMultiCamera.sensorSyncType [static, enum, public]
+     *
+     * <p>The accuracy of frame timestamp synchronization between physical cameras</p>
+     */
+    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE,
+
+    ANDROID_LOGICAL_MULTI_CAMERA_END_3_3,
+
+};
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
+
+/** android.control.aeMode enumeration values added since v3.2
+ * @see ANDROID_CONTROL_AE_MODE
+ */
+enum CameraMetadataEnumAndroidControlAeMode :
+        @3.2::CameraMetadataEnumAndroidControlAeMode {
+    ANDROID_CONTROL_AE_MODE_ON_EXTERNAL_FLASH,
+};
+
+/** android.control.captureIntent enumeration values added since v3.2
+ * @see ANDROID_CONTROL_CAPTURE_INTENT
+ */
+enum CameraMetadataEnumAndroidControlCaptureIntent :
+        @3.2::CameraMetadataEnumAndroidControlCaptureIntent {
+    ANDROID_CONTROL_CAPTURE_INTENT_MOTION_TRACKING,
+};
+
+/** android.control.afSceneChange enumeration values
+ * @see ANDROID_CONTROL_AF_SCENE_CHANGE
+ */
+enum CameraMetadataEnumAndroidControlAfSceneChange : uint32_t {
+    ANDROID_CONTROL_AF_SCENE_CHANGE_NOT_DETECTED,
+    ANDROID_CONTROL_AF_SCENE_CHANGE_DETECTED,
+};
+
+/** android.lens.poseReference enumeration values
+ * @see ANDROID_LENS_POSE_REFERENCE
+ */
+enum CameraMetadataEnumAndroidLensPoseReference : uint32_t {
+    ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA,
+    ANDROID_LENS_POSE_REFERENCE_GYROSCOPE,
+};
+
+/** android.request.availableCapabilities enumeration values added since v3.2
+ * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
+ */
+enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
+        @3.2::CameraMetadataEnumAndroidRequestAvailableCapabilities {
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING,
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA,
+};
+
+/** android.logicalMultiCamera.sensorSyncType enumeration values
+ * @see ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE
+ */
+enum CameraMetadataEnumAndroidLogicalMultiCameraSensorSyncType : uint32_t {
+    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE,
+    ANDROID_LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED,
+};
+
+/** android.info.supportedHardwareLevel enumeration values added since v3.2
+ * @see ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL
+ */
+enum CameraMetadataEnumAndroidInfoSupportedHardwareLevel :
+        @3.2::CameraMetadataEnumAndroidInfoSupportedHardwareLevel {
+    ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL,
+};
+
+/** android.statistics.oisDataMode enumeration values
+ * @see ANDROID_STATISTICS_OIS_DATA_MODE
+ */
+enum CameraMetadataEnumAndroidStatisticsOisDataMode : uint32_t {
+    ANDROID_STATISTICS_OIS_DATA_MODE_OFF,
+    ANDROID_STATISTICS_OIS_DATA_MODE_ON,
+};
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index c0b3591..31c5fdd 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -3,7 +3,8 @@
     defaults: ["hidl_defaults"],
     proprietary: true,
     relative_install_path: "hw",
-    srcs: ["CameraProvider.cpp"],
+    srcs: ["CameraProvider.cpp",
+           "ExternalCameraProvider.cpp"],
     shared_libs: [
         "libhidlbase",
         "libhidltransport",
@@ -12,9 +13,12 @@
         "android.hardware.camera.device@1.0",
         "android.hardware.camera.device@3.2",
         "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
         "camera.device@1.0-impl",
         "camera.device@3.2-impl",
         "camera.device@3.3-impl",
+        "camera.device@3.4-impl",
+        "camera.device@3.4-external-impl",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.common@1.0",
         "android.hardware.graphics.mapper@2.0",
@@ -22,11 +26,16 @@
         "android.hidl.memory@1.0",
         "liblog",
         "libhardware",
-        "libcamera_metadata"
+        "libcamera_metadata",
+        "libtinyxml2"
+    ],
+    header_libs: [
+        "camera.device@3.4-impl_headers",
+        "camera.device@3.4-external-impl_headers"
     ],
     static_libs: [
-        "android.hardware.camera.common@1.0-helper"
-    ]
+        "android.hardware.camera.common@1.0-helper",
+    ],
 }
 
 cc_binary {
@@ -46,6 +55,29 @@
         "android.hardware.camera.device@1.0",
         "android.hardware.camera.device@3.2",
         "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.provider@2.4",
+        "android.hardware.camera.common@1.0",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.camera.provider@2.4-external-service",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    relative_install_path: "hw",
+    srcs: ["external-service.cpp"],
+    compile_multilib: "32",
+    init_rc: ["android.hardware.camera.provider@2.4-external-service.rc"],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libbinder",
+        "liblog",
+        "libutils",
+        "android.hardware.camera.device@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.common@1.0",
     ],
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
index 8c5af8e..8e37b26 100644
--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -19,8 +19,10 @@
 #include <android/log.h>
 
 #include "CameraProvider.h"
+#include "ExternalCameraProvider.h"
 #include "CameraDevice_1_0.h"
 #include "CameraDevice_3_3.h"
+#include "CameraDevice_3_4.h"
 #include <cutils/properties.h>
 #include <string.h>
 #include <utils/Trace.h>
@@ -35,10 +37,12 @@
 
 namespace {
 const char *kLegacyProviderName = "legacy/0";
+const char *kExternalProviderName = "external/0";
 // "device@<version>/legacy/<id>"
 const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)");
 const char *kHAL3_2 = "3.2";
 const char *kHAL3_3 = "3.3";
+const char *kHAL3_4 = "3.4";
 const char *kHAL1_0 = "1.0";
 const int kMaxCameraDeviceNameLen = 128;
 const int kMaxCameraIdLen = 16;
@@ -238,12 +242,16 @@
     if (deviceVersion != CAMERA_DEVICE_API_VERSION_1_0 &&
             deviceVersion != CAMERA_DEVICE_API_VERSION_3_2 &&
             deviceVersion != CAMERA_DEVICE_API_VERSION_3_3 &&
-            deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 ) {
+            deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 &&
+            deviceVersion != CAMERA_DEVICE_API_VERSION_3_5) {
         return hidl_string("");
     }
     bool isV1 = deviceVersion == CAMERA_DEVICE_API_VERSION_1_0;
     int versionMajor = isV1 ? 1 : 3;
     int versionMinor = isV1 ? 0 : mPreferredHal3MinorVersion;
+    if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
+        versionMinor = 4;
+    }
     char deviceName[kMaxCameraDeviceNameLen];
     snprintf(deviceName, sizeof(deviceName), "device@%d.%d/legacy/%s",
             versionMajor, versionMinor, cameraId.c_str());
@@ -299,7 +307,8 @@
             break;
         default:
             ALOGW("Unknown minor camera device HAL version %d in property "
-                    "'camera.wrapper.hal3TrebleMinorVersion', defaulting to 3", mPreferredHal3MinorVersion);
+                    "'camera.wrapper.hal3TrebleMinorVersion', defaulting to 3",
+                    mPreferredHal3MinorVersion);
             mPreferredHal3MinorVersion = 3;
     }
 
@@ -347,6 +356,7 @@
             case CAMERA_DEVICE_API_VERSION_3_2:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_4:
+            case CAMERA_DEVICE_API_VERSION_3_5:
                 // in support
                 break;
             case CAMERA_DEVICE_API_VERSION_2_0:
@@ -535,10 +545,27 @@
         return Void();
     }
 
+    sp<android::hardware::camera::device::V3_2::ICameraDevice> device;
+    if (deviceVersion == kHAL3_4) {
+        ALOGV("Constructing v3.4 camera device");
+        sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl =
+            new android::hardware::camera::device::V3_4::implementation::CameraDevice(
+                    mModule, cameraId, mCameraDeviceNames);
+        if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+            ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+            device = nullptr;
+            _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+            return Void();
+        }
+
+        device = deviceImpl;
+        _hidl_cb (Status::OK, device);
+        return Void();
+    }
+
     // Since some Treble HAL revisions can map to the same legacy HAL version(s), we default
     // to the newest possible Treble HAL revision, but allow for override if needed via
     // system property.
-    sp<android::hardware::camera::device::V3_2::ICameraDevice> device;
     switch (mPreferredHal3MinorVersion) {
         case 2: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.2
             ALOGV("Constructing v3.2 camera device");
@@ -579,20 +606,24 @@
 }
 
 ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) {
-    if (strcmp(name, kLegacyProviderName) != 0) {
-        return nullptr;
+    if (strcmp(name, kLegacyProviderName) == 0) {
+        CameraProvider* provider = new CameraProvider();
+        if (provider == nullptr) {
+            ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);
+            return nullptr;
+        }
+        if (provider->isInitFailed()) {
+            ALOGE("%s: camera provider init failed!", __FUNCTION__);
+            delete provider;
+            return nullptr;
+        }
+        return provider;
+    } else if (strcmp(name, kExternalProviderName) == 0) {
+        ExternalCameraProvider* provider = new ExternalCameraProvider();
+        return provider;
     }
-    CameraProvider* provider = new CameraProvider();
-    if (provider == nullptr) {
-        ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);
-        return nullptr;
-    }
-    if (provider->isInitFailed()) {
-        ALOGE("%s: camera provider init failed!", __FUNCTION__);
-        delete provider;
-        return nullptr;
-    }
-    return provider;
+    ALOGE("%s: unknown instance name: %s", __FUNCTION__, name);
+    return nullptr;
 }
 
 } // namespace implementation
diff --git a/camera/provider/2.4/default/ExternalCameraProvider.cpp b/camera/provider/2.4/default/ExternalCameraProvider.cpp
new file mode 100644
index 0000000..7657fa3
--- /dev/null
+++ b/camera/provider/2.4/default/ExternalCameraProvider.cpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamPvdr@2.4-external"
+//#define LOG_NDEBUG 0
+#include <log/log.h>
+
+#include <regex>
+#include <sys/inotify.h>
+#include <errno.h>
+#include <linux/videodev2.h>
+#include "ExternalCameraProvider.h"
+#include "ExternalCameraDevice_3_4.h"
+#include "tinyxml2.h" // XML parsing
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_4 {
+namespace implementation {
+
+namespace {
+// "device@<version>/external/<id>"
+const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/external/(.+)");
+const int kMaxDevicePathLen = 256;
+const char* kDevicePath = "/dev/";
+
+bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
+                     std::string* cameraId) {
+    std::string deviceNameStd(deviceName.c_str());
+    std::smatch sm;
+    if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) {
+        if (deviceVersion != nullptr) {
+            *deviceVersion = sm[1];
+        }
+        if (cameraId != nullptr) {
+            *cameraId = sm[2];
+        }
+        return true;
+    }
+    return false;
+}
+
+} // anonymous namespace
+
+ExternalCameraProvider::ExternalCameraProvider() :
+        mHotPlugThread(this) {
+    mHotPlugThread.run("ExtCamHotPlug", PRIORITY_BACKGROUND);
+}
+
+ExternalCameraProvider::~ExternalCameraProvider() {
+    mHotPlugThread.requestExit();
+}
+
+
+Return<Status> ExternalCameraProvider::setCallback(
+        const sp<ICameraProviderCallback>& callback) {
+    Mutex::Autolock _l(mLock);
+    mCallbacks = callback;
+    return Status::OK;
+}
+
+Return<void> ExternalCameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) {
+    // No vendor tag support for USB camera
+    hidl_vec<VendorTagSection> zeroSections;
+    _hidl_cb(Status::OK, zeroSections);
+    return Void();
+}
+
+Return<void> ExternalCameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) {
+    std::vector<hidl_string> deviceNameList;
+    for (auto const& kvPair : mCameraStatusMap) {
+        if (kvPair.second == CameraDeviceStatus::PRESENT) {
+            deviceNameList.push_back(kvPair.first);
+        }
+    }
+    hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList);
+    ALOGV("ExtCam: number of cameras is %zu", deviceNameList.size());
+    _hidl_cb(Status::OK, hidlDeviceNameList);
+    return Void();
+}
+
+Return<void> ExternalCameraProvider::isSetTorchModeSupported(
+        isSetTorchModeSupported_cb _hidl_cb) {
+    // No torch mode support for USB camera
+    _hidl_cb (Status::OK, false);
+    return Void();
+}
+
+Return<void> ExternalCameraProvider::getCameraDeviceInterface_V1_x(
+        const hidl_string&,
+        getCameraDeviceInterface_V1_x_cb _hidl_cb) {
+    // External Camera HAL does not support HAL1
+    _hidl_cb(Status::OPERATION_NOT_SUPPORTED, nullptr);
+    return Void();
+}
+
+Return<void> ExternalCameraProvider::getCameraDeviceInterface_V3_x(
+        const hidl_string& cameraDeviceName,
+        getCameraDeviceInterface_V3_x_cb _hidl_cb) {
+
+    std::string cameraId, deviceVersion;
+    bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId);
+    if (!match) {
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+        return Void();
+    }
+
+    if (mCameraStatusMap.count(cameraDeviceName) == 0 ||
+            mCameraStatusMap[cameraDeviceName] != CameraDeviceStatus::PRESENT) {
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+        return Void();
+    }
+
+    ALOGV("Constructing v3.4 external camera device");
+    sp<device::V3_2::ICameraDevice> device;
+    sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl =
+            new device::V3_4::implementation::ExternalCameraDevice(
+                    cameraId);
+    if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+        ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+        device = nullptr;
+        _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+        return Void();
+    }
+    device = deviceImpl;
+
+    _hidl_cb (Status::OK, device);
+
+    return Void();
+}
+
+void ExternalCameraProvider::addExternalCamera(const char* devName) {
+    ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
+    Mutex::Autolock _l(mLock);
+    std::string deviceName = std::string("device@3.4/external/") + devName;
+    mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
+    if (mCallbacks != nullptr) {
+        mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::PRESENT);
+    }
+}
+
+void ExternalCameraProvider::deviceAdded(const char* devName) {
+    int fd = -1;
+    if ((fd = ::open(devName, O_RDWR)) < 0) {
+        ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno));
+        return;
+    }
+
+    do {
+        struct v4l2_capability capability;
+        int ret = ioctl(fd, VIDIOC_QUERYCAP, &capability);
+        if (ret < 0) {
+            ALOGE("%s v4l2 QUERYCAP %s failed", __FUNCTION__, devName);
+            break;
+        }
+
+        if (!(capability.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
+            ALOGW("%s device %s does not support VIDEO_CAPTURE", __FUNCTION__, devName);
+            break;
+        }
+
+        addExternalCamera(devName);
+    } while (0);
+
+    close(fd);
+    return;
+}
+
+void ExternalCameraProvider::deviceRemoved(const char* devName) {
+    Mutex::Autolock _l(mLock);
+    std::string deviceName = std::string("device@3.4/external/") + devName;
+    if (mCameraStatusMap.find(deviceName) != mCameraStatusMap.end()) {
+        mCameraStatusMap.erase(deviceName);
+        if (mCallbacks != nullptr) {
+            mCallbacks->cameraDeviceStatusChange(deviceName, CameraDeviceStatus::NOT_PRESENT);
+        }
+    } else {
+        ALOGE("%s: cannot find camera device %s", __FUNCTION__, devName);
+    }
+}
+
+std::unordered_set<std::string>
+ExternalCameraProvider::HotplugThread::initInternalDevices() {
+    std::unordered_set<std::string> ret;
+    using device::V3_4::implementation::ExternalCameraDeviceConfig;
+    const char* configPath = ExternalCameraDeviceConfig::kDefaultCfgPath;
+
+    using namespace tinyxml2;
+
+    XMLDocument configXml;
+    XMLError err = configXml.LoadFile(configPath);
+    if (err != XML_SUCCESS) {
+        ALOGE("%s: Unable to load external camera config file '%s'. Error: %s",
+                __FUNCTION__, configPath, XMLDocument::ErrorIDToName(err));
+    } else {
+        ALOGI("%s: load external camera config succeed!", __FUNCTION__);
+    }
+
+    XMLElement *extCam = configXml.FirstChildElement("ExternalCamera");
+    if (extCam == nullptr) {
+        ALOGI("%s: no external camera config specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement *providerCfg = extCam->FirstChildElement("Provider");
+    if (providerCfg == nullptr) {
+        ALOGI("%s: no external camera provider config specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement *ignore = providerCfg->FirstChildElement("ignore");
+    if (ignore == nullptr) {
+        ALOGI("%s: no internal ignored device specified", __FUNCTION__);
+        return ret;
+    }
+
+    XMLElement *id = ignore->FirstChildElement("id");
+    while (id != nullptr) {
+        const char* text = id->GetText();
+        if (text != nullptr) {
+            ret.insert(text);
+            ALOGI("%s: device %s will be ignored by external camera provider",
+                    __FUNCTION__, text);
+        }
+        id = id->NextSiblingElement("id");
+    }
+
+    return ret;
+}
+
+ExternalCameraProvider::HotplugThread::HotplugThread(ExternalCameraProvider* parent) :
+        Thread(/*canCallJava*/false),
+        mParent(parent),
+        mInternalDevices(initInternalDevices()) {}
+
+ExternalCameraProvider::HotplugThread::~HotplugThread() {}
+
+bool ExternalCameraProvider::HotplugThread::threadLoop() {
+    // Find existing /dev/video* devices
+    DIR* devdir = opendir(kDevicePath);
+    if(devdir == 0) {
+        ALOGE("%s: cannot open %s! Exiting threadloop", __FUNCTION__, kDevicePath);
+        return false;
+    }
+
+    struct dirent* de;
+    while ((de = readdir(devdir)) != 0) {
+        // Find external v4l devices that's existing before we start watching and add them
+        if (!strncmp("video", de->d_name, 5)) {
+            // TODO: This might reject some valid devices. Ex: internal is 33 and a device named 3
+            //       is added.
+            std::string deviceId(de->d_name + 5);
+            if (mInternalDevices.count(deviceId) == 0) {
+                ALOGV("Non-internal v4l device %s found", de->d_name);
+                char v4l2DevicePath[kMaxDevicePathLen];
+                snprintf(v4l2DevicePath, kMaxDevicePathLen,
+                        "%s%s", kDevicePath, de->d_name);
+                mParent->deviceAdded(v4l2DevicePath);
+            }
+        }
+    }
+    closedir(devdir);
+
+    // Watch new video devices
+    mINotifyFD = inotify_init();
+    if (mINotifyFD < 0) {
+        ALOGE("%s: inotify init failed! Exiting threadloop", __FUNCTION__);
+        return true;
+    }
+
+    mWd = inotify_add_watch(mINotifyFD, kDevicePath, IN_CREATE | IN_DELETE);
+    if (mWd < 0) {
+        ALOGE("%s: inotify add watch failed! Exiting threadloop", __FUNCTION__);
+        return true;
+    }
+
+    ALOGI("%s start monitoring new V4L2 devices", __FUNCTION__);
+
+    bool done = false;
+    char eventBuf[512];
+    while (!done) {
+        int offset = 0;
+        int ret = read(mINotifyFD, eventBuf, sizeof(eventBuf));
+        if (ret >= (int)sizeof(struct inotify_event)) {
+            while (offset < ret) {
+                struct inotify_event* event = (struct inotify_event*)&eventBuf[offset];
+                if (event->wd == mWd) {
+                    if (!strncmp("video", event->name, 5)) {
+                        std::string deviceId(event->name + 5);
+                        if (mInternalDevices.count(deviceId) == 0) {
+                            char v4l2DevicePath[kMaxDevicePathLen];
+                            snprintf(v4l2DevicePath, kMaxDevicePathLen,
+                                    "%s%s", kDevicePath, event->name);
+                            if (event->mask & IN_CREATE) {
+                                mParent->deviceAdded(v4l2DevicePath);
+                            }
+                            if (event->mask & IN_DELETE) {
+                                mParent->deviceRemoved(v4l2DevicePath);
+                            }
+                        }
+                    }
+                }
+                offset += sizeof(struct inotify_event) + event->len;
+            }
+        }
+    }
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V2_4
+}  // namespace provider
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/provider/2.4/default/ExternalCameraProvider.h b/camera/provider/2.4/default/ExternalCameraProvider.h
new file mode 100644
index 0000000..64a8878
--- /dev/null
+++ b/camera/provider/2.4/default/ExternalCameraProvider.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_EXTCAMERAPROVIDER_H
+#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_EXTCAMERAPROVIDER_H
+
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include "utils/Mutex.h"
+#include "utils/Thread.h"
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_4 {
+namespace implementation {
+
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::VendorTagSection;
+using ::android::hardware::camera::provider::V2_4::ICameraProvider;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+struct ExternalCameraProvider : public ICameraProvider {
+    ExternalCameraProvider();
+    ~ExternalCameraProvider();
+
+    // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+    Return<Status> setCallback(const sp<ICameraProviderCallback>& callback) override;
+
+    Return<void> getVendorTags(getVendorTags_cb _hidl_cb) override;
+
+    Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override;
+
+    Return<void> isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override;
+
+    Return<void> getCameraDeviceInterface_V1_x(
+            const hidl_string&,
+            getCameraDeviceInterface_V1_x_cb) override;
+    Return<void> getCameraDeviceInterface_V3_x(
+            const hidl_string&,
+            getCameraDeviceInterface_V3_x_cb) override;
+
+private:
+
+    void addExternalCamera(const char* devName);
+
+    void deviceAdded(const char* devName);
+
+    void deviceRemoved(const char* devName);
+
+    class HotplugThread : public android::Thread {
+    public:
+        HotplugThread(ExternalCameraProvider* parent);
+        ~HotplugThread();
+
+        virtual bool threadLoop() override;
+
+    private:
+        static std::unordered_set<std::string> initInternalDevices();
+
+        ExternalCameraProvider* mParent = nullptr;
+        const std::unordered_set<std::string> mInternalDevices;
+
+        int mINotifyFD = -1;
+        int mWd = -1;
+    };
+
+    Mutex mLock;
+    sp<ICameraProviderCallback> mCallbacks = nullptr;
+    std::unordered_map<std::string, CameraDeviceStatus> mCameraStatusMap; // camera id -> status
+    HotplugThread mHotPlugThread;
+};
+
+
+
+}  // namespace implementation
+}  // namespace V2_4
+}  // namespace provider
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_EXTCAMERAPROVIDER_H
diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc
new file mode 100644
index 0000000..acdb200
--- /dev/null
+++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-external-service.rc
@@ -0,0 +1,7 @@
+service vendor.camera-provider-2-4-ext /vendor/bin/hw/android.hardware.camera.provider@2.4-external-service
+    class hal
+    user cameraserver
+    group audio camera input drmrpc usb
+    ioprio rt 4
+    capabilities SYS_NICE
+    writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks
diff --git a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc
index 2bf309b..c919628 100644
--- a/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc
+++ b/camera/provider/2.4/default/android.hardware.camera.provider@2.4-service.rc
@@ -1,4 +1,4 @@
-service camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service
+service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service
     class hal
     user cameraserver
     group audio camera input drmrpc
diff --git a/camera/provider/2.4/default/external-service.cpp b/camera/provider/2.4/default/external-service.cpp
new file mode 100644
index 0000000..f91aa59
--- /dev/null
+++ b/camera/provider/2.4/default/external-service.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.camera.provider@2.4-external-service"
+
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <hidl/LegacySupport.h>
+
+#include <binder/ProcessState.h>
+
+using android::hardware::camera::provider::V2_4::ICameraProvider;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main()
+{
+    ALOGI("External camera provider service is starting.");
+    // The camera HAL may communicate to other vendor components via
+    // /dev/vndbinder
+    android::ProcessState::initWithDriver("/dev/vndbinder");
+    return defaultPassthroughServiceImplementation<ICameraProvider>("external/0", /*maxThreads*/ 6);
+}
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 81d3de1..7bc4253 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -35,6 +35,7 @@
         "android.hardware.camera.device@1.0",
         "android.hardware.camera.device@3.2",
         "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
         "android.hardware.camera.provider@2.4",
         "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.mapper@2.0",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index e4cf9af..1405ea9 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2016-2018 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
 #include <mutex>
 #include <regex>
 #include <unordered_map>
+#include <unordered_set>
 #include <condition_variable>
 
 #include <inttypes.h>
@@ -27,6 +28,8 @@
 #include <android/hardware/camera/device/1.0/ICameraDevice.h>
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
 #include <android/hardware/camera/provider/2.4/ICameraProvider.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <binder/MemoryHeapBase.h>
@@ -46,6 +49,7 @@
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
 
+using namespace ::android::hardware::camera::device;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
 using ::android::hardware::hidl_handle;
@@ -77,7 +81,6 @@
 using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
 using ::android::hardware::camera::device::V3_2::NotifyMsg;
 using ::android::hardware::camera::device::V3_2::RequestTemplate;
-using ::android::hardware::camera::device::V3_2::Stream;
 using ::android::hardware::camera::device::V3_2::StreamType;
 using ::android::hardware::camera::device::V3_2::StreamRotation;
 using ::android::hardware::camera::device::V3_2::StreamConfiguration;
@@ -128,9 +131,11 @@
 namespace {
     // "device@<version>/legacy/<id>"
     const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
+    const int CAMERA_DEVICE_API_VERSION_3_4 = 0x304;
     const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303;
     const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
     const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
+    const char *kHAL3_4 = "3.4";
     const char *kHAL3_3 = "3.3";
     const char *kHAL3_2 = "3.2";
     const char *kHAL1_0 = "1.0";
@@ -164,7 +169,9 @@
             return -1;
         }
 
-        if (version.compare(kHAL3_3) == 0) {
+        if (version.compare(kHAL3_4) == 0) {
+            return CAMERA_DEVICE_API_VERSION_3_4;
+        } else if (version.compare(kHAL3_3) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_3;
         } else if (version.compare(kHAL3_2) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_2;
@@ -526,12 +533,16 @@
      }
     };
 
-    struct DeviceCb : public ICameraDeviceCallback {
+    struct DeviceCb : public V3_4::ICameraDeviceCallback {
         DeviceCb(CameraHidlTest *parent) : mParent(parent) {}
+        Return<void> processCaptureResult_3_4(
+                const hidl_vec<V3_4::CaptureResult>& results) override;
         Return<void> processCaptureResult(const hidl_vec<CaptureResult>& results) override;
         Return<void> notify(const hidl_vec<NotifyMsg>& msgs) override;
 
      private:
+        bool processCaptureResultLocked(const CaptureResult& results);
+
         CameraHidlTest *mParent;               // Parent object
     };
 
@@ -611,13 +622,29 @@
     void openEmptyDeviceSession(const std::string &name,
             sp<ICameraProvider> provider,
             sp<ICameraDeviceSession> *session /*out*/,
-            sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
             camera_metadata_t **staticMeta /*out*/);
-    void configurePreviewStream(const std::string &name,
+    void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
+            sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
+            sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/);
+    void createStreamConfiguration(const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
+            StreamConfigurationMode configMode,
+            ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2,
+            ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4);
+
+    void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
+            sp<ICameraProvider> provider,
+            const AvailableStream *previewThreshold,
+            const std::unordered_set<std::string>& physicalIds,
+            sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
+            V3_2::Stream* previewStream /*out*/,
+            device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/,
+            bool *supportsPartialResults /*out*/,
+            uint32_t *partialResultCount /*out*/);
+    void configurePreviewStream(const std::string &name, int32_t deviceVersion,
             sp<ICameraProvider> provider,
             const AvailableStream *previewThreshold,
             sp<ICameraDeviceSession> *session /*out*/,
-            Stream *previewStream /*out*/,
+            V3_2::Stream *previewStream /*out*/,
             HalStreamConfiguration *halStreamConfig /*out*/,
             bool *supportsPartialResults /*out*/,
             uint32_t *partialResultCount /*out*/);
@@ -625,6 +652,9 @@
             std::vector<AvailableStream> &outputStreams,
             const AvailableStream *threshold = nullptr);
     static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
+    static Status isLogicalMultiCamera(camera_metadata_t *staticMeta);
+    static Status getPhysicalCameraIds(camera_metadata_t *staticMeta,
+            std::unordered_set<std::string> *physicalIds/*out*/);
     static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
             AvailableStream &hfrStream);
     static Status isZSLModeAvailable(camera_metadata_t *staticMeta);
@@ -827,6 +857,27 @@
     return Void();
 }
 
+Return<void> CameraHidlTest::DeviceCb::processCaptureResult_3_4(
+        const hidl_vec<V3_4::CaptureResult>& results) {
+
+    if (nullptr == mParent) {
+        return Void();
+    }
+
+    bool notify = false;
+    std::unique_lock<std::mutex> l(mParent->mLock);
+    for (size_t i = 0 ; i < results.size(); i++) {
+        notify = processCaptureResultLocked(results[i].v3_2);
+    }
+
+    l.unlock();
+    if (notify) {
+        mParent->mResultCondition.notify_one();
+    }
+
+    return Void();
+}
+
 Return<void> CameraHidlTest::DeviceCb::processCaptureResult(
         const hidl_vec<CaptureResult>& results) {
     if (nullptr == mParent) {
@@ -836,121 +887,7 @@
     bool notify = false;
     std::unique_lock<std::mutex> l(mParent->mLock);
     for (size_t i = 0 ; i < results.size(); i++) {
-        uint32_t frameNumber = results[i].frameNumber;
-
-        if ((results[i].result.size() == 0) &&
-                (results[i].outputBuffers.size() == 0) &&
-                (results[i].inputBuffer.buffer == nullptr) &&
-                (results[i].fmqResultSize == 0)) {
-            ALOGE("%s: No result data provided by HAL for frame %d result count: %d",
-                  __func__, frameNumber, (int) results[i].fmqResultSize);
-            ADD_FAILURE();
-            break;
-        }
-
-        ssize_t idx = mParent->mInflightMap.indexOfKey(frameNumber);
-        if (::android::NAME_NOT_FOUND == idx) {
-            ALOGE("%s: Unexpected frame number! received: %u",
-                  __func__, frameNumber);
-            ADD_FAILURE();
-            break;
-        }
-
-        bool isPartialResult = false;
-        bool hasInputBufferInRequest = false;
-        InFlightRequest *request = mParent->mInflightMap.editValueAt(idx);
-        ::android::hardware::camera::device::V3_2::CameraMetadata resultMetadata;
-        size_t resultSize = 0;
-        if (results[i].fmqResultSize > 0) {
-            resultMetadata.resize(results[i].fmqResultSize);
-            if (request->resultQueue == nullptr) {
-                ADD_FAILURE();
-                break;
-            }
-            if (!request->resultQueue->read(resultMetadata.data(),
-                    results[i].fmqResultSize)) {
-                ALOGE("%s: Frame %d: Cannot read camera metadata from fmq,"
-                        "size = %" PRIu64, __func__, frameNumber,
-                        results[i].fmqResultSize);
-                ADD_FAILURE();
-                break;
-            }
-            resultSize = resultMetadata.size();
-        } else if (results[i].result.size() > 0) {
-            resultMetadata.setToExternal(const_cast<uint8_t *>(
-                    results[i].result.data()), results[i].result.size());
-            resultSize = resultMetadata.size();
-        }
-
-        if (!request->usePartialResult && (resultSize > 0) &&
-                (results[i].partialResult != 1)) {
-            ALOGE("%s: Result is malformed for frame %d: partial_result %u "
-                    "must be 1  if partial result is not supported", __func__,
-                    frameNumber, results[i].partialResult);
-            ADD_FAILURE();
-            break;
-        }
-
-        if (results[i].partialResult != 0) {
-            request->partialResultCount = results[i].partialResult;
-        }
-
-        // Check if this result carries only partial metadata
-        if (request->usePartialResult && (resultSize > 0)) {
-            if ((results[i].partialResult > request->numPartialResults) ||
-                    (results[i].partialResult < 1)) {
-                ALOGE("%s: Result is malformed for frame %d: partial_result %u"
-                        " must be  in the range of [1, %d] when metadata is "
-                        "included in the result", __func__, frameNumber,
-                        results[i].partialResult, request->numPartialResults);
-                ADD_FAILURE();
-                break;
-            }
-            request->collectedResult.append(
-                    reinterpret_cast<const camera_metadata_t*>(
-                            resultMetadata.data()));
-
-            isPartialResult =
-                    (results[i].partialResult < request->numPartialResults);
-        }
-
-        hasInputBufferInRequest = request->hasInputBuffer;
-
-        // Did we get the (final) result metadata for this capture?
-        if ((resultSize > 0) && !isPartialResult) {
-            if (request->haveResultMetadata) {
-                ALOGE("%s: Called multiple times with metadata for frame %d",
-                      __func__, frameNumber);
-                ADD_FAILURE();
-                break;
-            }
-            request->haveResultMetadata = true;
-            request->collectedResult.sort();
-        }
-
-        uint32_t numBuffersReturned = results[i].outputBuffers.size();
-        if (results[i].inputBuffer.buffer != nullptr) {
-            if (hasInputBufferInRequest) {
-                numBuffersReturned += 1;
-            } else {
-                ALOGW("%s: Input buffer should be NULL if there is no input"
-                        " buffer sent in the request", __func__);
-            }
-        }
-        request->numBuffersLeft -= numBuffersReturned;
-        if (request->numBuffersLeft < 0) {
-            ALOGE("%s: Too many buffers returned for frame %d", __func__,
-                    frameNumber);
-            ADD_FAILURE();
-            break;
-        }
-
-        request->resultOutputBuffers.appendArray(results[i].outputBuffers.data(),
-                results[i].outputBuffers.size());
-        // If shutter event is received notify the pending threads.
-        if (request->shutterTimestamp != 0) {
-            notify = true;
-        }
+        notify = processCaptureResultLocked(results[i]);
     }
 
     l.unlock();
@@ -961,6 +898,126 @@
     return Void();
 }
 
+bool CameraHidlTest::DeviceCb::processCaptureResultLocked(const CaptureResult& results) {
+    bool notify = false;
+    uint32_t frameNumber = results.frameNumber;
+
+    if ((results.result.size() == 0) &&
+            (results.outputBuffers.size() == 0) &&
+            (results.inputBuffer.buffer == nullptr) &&
+            (results.fmqResultSize == 0)) {
+        ALOGE("%s: No result data provided by HAL for frame %d result count: %d",
+                __func__, frameNumber, (int) results.fmqResultSize);
+        ADD_FAILURE();
+        return notify;
+    }
+
+    ssize_t idx = mParent->mInflightMap.indexOfKey(frameNumber);
+    if (::android::NAME_NOT_FOUND == idx) {
+        ALOGE("%s: Unexpected frame number! received: %u",
+                __func__, frameNumber);
+        ADD_FAILURE();
+        return notify;
+    }
+
+    bool isPartialResult = false;
+    bool hasInputBufferInRequest = false;
+    InFlightRequest *request = mParent->mInflightMap.editValueAt(idx);
+    ::android::hardware::camera::device::V3_2::CameraMetadata resultMetadata;
+    size_t resultSize = 0;
+    if (results.fmqResultSize > 0) {
+        resultMetadata.resize(results.fmqResultSize);
+        if (request->resultQueue == nullptr) {
+            ADD_FAILURE();
+            return notify;
+        }
+        if (!request->resultQueue->read(resultMetadata.data(),
+                    results.fmqResultSize)) {
+            ALOGE("%s: Frame %d: Cannot read camera metadata from fmq,"
+                    "size = %" PRIu64, __func__, frameNumber,
+                    results.fmqResultSize);
+            ADD_FAILURE();
+            return notify;
+        }
+        resultSize = resultMetadata.size();
+    } else if (results.result.size() > 0) {
+        resultMetadata.setToExternal(const_cast<uint8_t *>(
+                    results.result.data()), results.result.size());
+        resultSize = resultMetadata.size();
+    }
+
+    if (!request->usePartialResult && (resultSize > 0) &&
+            (results.partialResult != 1)) {
+        ALOGE("%s: Result is malformed for frame %d: partial_result %u "
+                "must be 1  if partial result is not supported", __func__,
+                frameNumber, results.partialResult);
+        ADD_FAILURE();
+        return notify;
+    }
+
+    if (results.partialResult != 0) {
+        request->partialResultCount = results.partialResult;
+    }
+
+    // Check if this result carries only partial metadata
+    if (request->usePartialResult && (resultSize > 0)) {
+        if ((results.partialResult > request->numPartialResults) ||
+                (results.partialResult < 1)) {
+            ALOGE("%s: Result is malformed for frame %d: partial_result %u"
+                    " must be  in the range of [1, %d] when metadata is "
+                    "included in the result", __func__, frameNumber,
+                    results.partialResult, request->numPartialResults);
+            ADD_FAILURE();
+            return notify;
+        }
+        request->collectedResult.append(
+                reinterpret_cast<const camera_metadata_t*>(
+                    resultMetadata.data()));
+
+        isPartialResult =
+            (results.partialResult < request->numPartialResults);
+    }
+
+    hasInputBufferInRequest = request->hasInputBuffer;
+
+    // Did we get the (final) result metadata for this capture?
+    if ((resultSize > 0) && !isPartialResult) {
+        if (request->haveResultMetadata) {
+            ALOGE("%s: Called multiple times with metadata for frame %d",
+                    __func__, frameNumber);
+            ADD_FAILURE();
+            return notify;
+        }
+        request->haveResultMetadata = true;
+        request->collectedResult.sort();
+    }
+
+    uint32_t numBuffersReturned = results.outputBuffers.size();
+    if (results.inputBuffer.buffer != nullptr) {
+        if (hasInputBufferInRequest) {
+            numBuffersReturned += 1;
+        } else {
+            ALOGW("%s: Input buffer should be NULL if there is no input"
+                    " buffer sent in the request", __func__);
+        }
+    }
+    request->numBuffersLeft -= numBuffersReturned;
+    if (request->numBuffersLeft < 0) {
+        ALOGE("%s: Too many buffers returned for frame %d", __func__,
+                frameNumber);
+        ADD_FAILURE();
+        return notify;
+    }
+
+    request->resultOutputBuffers.appendArray(results.outputBuffers.data(),
+            results.outputBuffers.size());
+    // If shutter event is received notify the pending threads.
+    if (request->shutterTimestamp != 0) {
+        notify = true;
+    }
+    return notify;
+}
+
 Return<void> CameraHidlTest::DeviceCb::notify(
         const hidl_vec<NotifyMsg>& messages) {
     std::lock_guard<std::mutex> l(mParent->mLock);
@@ -1100,6 +1157,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 Return<void> ret;
@@ -1140,6 +1198,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
@@ -1879,6 +1938,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
@@ -1905,6 +1965,19 @@
                     // characteristics keys we've defined.
                     ASSERT_GT(entryCount, 0u);
                     ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount);
+
+                    camera_metadata_ro_entry entry;
+                    int retcode = find_camera_metadata_ro_entry(metadata,
+                            ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &entry);
+                    if ((0 == retcode) && (entry.count > 0)) {
+                        uint8_t hardwareLevel = entry.data.u8[0];
+                        ASSERT_TRUE(
+                                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED ||
+                                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
+                                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3);
+                    } else {
+                        ADD_FAILURE() << "Get camera hardware level failed!";
+                    }
                 });
                 ASSERT_TRUE(ret.isOk());
             }
@@ -1943,6 +2016,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
@@ -2067,6 +2141,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<ICameraDevice> device3_x;
@@ -2130,6 +2205,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
@@ -2152,12 +2228,14 @@
                     session = newSession;
                 });
                 ASSERT_TRUE(ret.isOk());
-                // Ensure that a device labeling itself as 3.3 can have its session interface cast
-                // to the 3.3 interface, and that lower versions can't be cast to it.
-                auto castResult = device::V3_3::ICameraDeviceSession::castFrom(session);
-                ASSERT_TRUE(castResult.isOk());
-                sp<device::V3_3::ICameraDeviceSession> sessionV3_3 = castResult;
-                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_3) {
+                // Ensure that a device labeling itself as 3.3/3.4 can have its session interface
+                // cast the 3.3/3.4 interface, and that lower versions can't be cast to it.
+                sp<device::V3_3::ICameraDeviceSession> sessionV3_3;
+                sp<device::V3_4::ICameraDeviceSession> sessionV3_4;
+                castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4);
+                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
+                    ASSERT_TRUE(sessionV3_4.get() != nullptr);
+                } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_3) {
                     ASSERT_TRUE(sessionV3_3.get() != nullptr);
                 } else {
                     ASSERT_TRUE(sessionV3_3.get() == nullptr);
@@ -2213,6 +2291,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
                 ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
@@ -2301,66 +2380,72 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
-
-                outputStreams.clear();
-                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
-                ASSERT_NE(0u, outputStreams.size());
-
-                int32_t streamId = 0;
-                for (auto& it : outputStreams) {
-                    Stream stream = {streamId,
-                                     StreamType::OUTPUT,
-                                     static_cast<uint32_t>(it.width),
-                                     static_cast<uint32_t>(it.height),
-                                     static_cast<PixelFormat>(it.format),
-                                     GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                                     0,
-                                     StreamRotation::ROTATION_0};
-                    ::android::hardware::hidl_vec<Stream> streams = {stream};
-                    StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE};
-                    if (session3_3 == nullptr) {
-                        ret = session->configureStreams(config,
-                                [streamId](Status s, HalStreamConfiguration halConfig) {
-                                    ASSERT_EQ(Status::OK, s);
-                                    ASSERT_EQ(1u, halConfig.streams.size());
-                                    ASSERT_EQ(halConfig.streams[0].id, streamId);
-                                });
-                    } else {
-                        ret = session3_3->configureStreams_3_3(config,
-                                [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
-                                    ASSERT_EQ(Status::OK, s);
-                                    ASSERT_EQ(1u, halConfig.streams.size());
-                                    ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
-                                });
-                    }
-                    ASSERT_TRUE(ret.isOk());
-                    streamId++;
-                }
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider,
+                &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
+
+        outputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
+        ASSERT_NE(0u, outputStreams.size());
+
+        int32_t streamId = 0;
+        for (auto& it : outputStreams) {
+            V3_2::Stream stream3_2;
+            stream3_2 = {streamId,
+                             StreamType::OUTPUT,
+                             static_cast<uint32_t>(it.width),
+                             static_cast<uint32_t>(it.height),
+                             static_cast<PixelFormat>(it.format),
+                             GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                             0,
+                             StreamRotation::ROTATION_0};
+            ::android::hardware::hidl_vec<V3_2::Stream> streams3_2 = {stream3_2};
+            ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+            ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+            createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
+                                      &config3_2, &config3_4);
+            if (session3_4 != nullptr) {
+                ret = session3_4->configureStreams_3_4(config3_4,
+                        [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(1u, halConfig.streams.size());
+                            ASSERT_EQ(halConfig.streams[0].v3_3.v3_2.id, streamId);
+                        });
+            } else if (session3_3 != nullptr) {
+                ret = session3_3->configureStreams_3_3(config3_2,
+                        [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(1u, halConfig.streams.size());
+                            ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
+                        });
+            } else {
+                ret = session->configureStreams(config3_2,
+                        [streamId](Status s, HalStreamConfiguration halConfig) {
+                            ASSERT_EQ(Status::OK, s);
+                            ASSERT_EQ(1u, halConfig.streams.size());
+                            ASSERT_EQ(halConfig.streams[0].id, streamId);
+                        });
+            }
+            ASSERT_TRUE(ret.isOk());
+            streamId++;
+        }
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2371,132 +2456,153 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
-
-                outputStreams.clear();
-                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
-                ASSERT_NE(0u, outputStreams.size());
-
-                int32_t streamId = 0;
-                Stream stream = {streamId++,
-                                 StreamType::OUTPUT,
-                                 static_cast<uint32_t>(0),
-                                 static_cast<uint32_t>(0),
-                                 static_cast<PixelFormat>(outputStreams[0].format),
-                                 GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                                 0,
-                                 StreamRotation::ROTATION_0};
-                ::android::hardware::hidl_vec<Stream> streams = {stream};
-                StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE};
-                if(session3_3 == nullptr) {
-                    ret = session->configureStreams(config,
-                        [](Status s, HalStreamConfiguration) {
-                            ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                                    (Status::INTERNAL_ERROR == s));
-                        });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config,
-                        [](Status s, device::V3_3::HalStreamConfiguration) {
-                            ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                                    (Status::INTERNAL_ERROR == s));
-                        });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                stream = {streamId++,
-                          StreamType::OUTPUT,
-                          static_cast<uint32_t>(UINT32_MAX),
-                          static_cast<uint32_t>(UINT32_MAX),
-                          static_cast<PixelFormat>(outputStreams[0].format),
-                          GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                          0,
-                          StreamRotation::ROTATION_0};
-                streams[0] = stream;
-                config = {streams, StreamConfigurationMode::NORMAL_MODE};
-                if(session3_3 == nullptr) {
-                    ret = session->configureStreams(config, [](Status s,
-                                HalStreamConfiguration) {
-                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                        });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config, [](Status s,
-                                device::V3_3::HalStreamConfiguration) {
-                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                        });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                for (auto& it : outputStreams) {
-                    stream = {streamId++,
-                              StreamType::OUTPUT,
-                              static_cast<uint32_t>(it.width),
-                              static_cast<uint32_t>(it.height),
-                              static_cast<PixelFormat>(UINT32_MAX),
-                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                              0,
-                              StreamRotation::ROTATION_0};
-                    streams[0] = stream;
-                    config = {streams, StreamConfigurationMode::NORMAL_MODE};
-                    if(session3_3 == nullptr) {
-                        ret = session->configureStreams(config,
-                                [](Status s, HalStreamConfiguration) {
-                                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                                });
-                    } else {
-                        ret = session3_3->configureStreams_3_3(config,
-                                [](Status s, device::V3_3::HalStreamConfiguration) {
-                                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                                });
-                    }
-                    ASSERT_TRUE(ret.isOk());
-
-                    stream = {streamId++,
-                              StreamType::OUTPUT,
-                              static_cast<uint32_t>(it.width),
-                              static_cast<uint32_t>(it.height),
-                              static_cast<PixelFormat>(it.format),
-                              GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                              0,
-                              static_cast<StreamRotation>(UINT32_MAX)};
-                    streams[0] = stream;
-                    config = {streams, StreamConfigurationMode::NORMAL_MODE};
-                    if(session3_3 == nullptr) {
-                        ret = session->configureStreams(config,
-                                [](Status s, HalStreamConfiguration) {
-                                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                                });
-                    } else {
-                        ret = session3_3->configureStreams_3_3(config,
-                                [](Status s, device::V3_3::HalStreamConfiguration) {
-                                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                                });
-                    }
-                    ASSERT_TRUE(ret.isOk());
-                }
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
+
+        outputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
+        ASSERT_NE(0u, outputStreams.size());
+
+        int32_t streamId = 0;
+        V3_2::Stream stream3_2 = {streamId++,
+                         StreamType::OUTPUT,
+                         static_cast<uint32_t>(0),
+                         static_cast<uint32_t>(0),
+                         static_cast<PixelFormat>(outputStreams[0].format),
+                         GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                         0,
+                         StreamRotation::ROTATION_0};
+        ::android::hardware::hidl_vec<V3_2::Stream> streams = {stream3_2};
+        ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+        ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+        createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                                  &config3_2, &config3_4);
+        if(session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                [](Status s, device::V3_4::HalStreamConfiguration) {
+                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                            (Status::INTERNAL_ERROR == s));
+                });
+        } else if(session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config3_2,
+                [](Status s, device::V3_3::HalStreamConfiguration) {
+                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                            (Status::INTERNAL_ERROR == s));
+                });
+        } else {
+            ret = session->configureStreams(config3_2,
+                [](Status s, HalStreamConfiguration) {
+                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                            (Status::INTERNAL_ERROR == s));
+                });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        stream3_2 = {streamId++,
+                  StreamType::OUTPUT,
+                  static_cast<uint32_t>(UINT32_MAX),
+                  static_cast<uint32_t>(UINT32_MAX),
+                  static_cast<PixelFormat>(outputStreams[0].format),
+                  GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                  0,
+                  StreamRotation::ROTATION_0};
+        streams[0] = stream3_2;
+        createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                &config3_2, &config3_4);
+        if(session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config3_4, [](Status s,
+                        device::V3_4::HalStreamConfiguration) {
+                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                });
+        } else if(session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config3_2, [](Status s,
+                        device::V3_3::HalStreamConfiguration) {
+                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                });
+        } else {
+            ret = session->configureStreams(config3_2, [](Status s,
+                        HalStreamConfiguration) {
+                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        for (auto& it : outputStreams) {
+            stream3_2 = {streamId++,
+                      StreamType::OUTPUT,
+                      static_cast<uint32_t>(it.width),
+                      static_cast<uint32_t>(it.height),
+                      static_cast<PixelFormat>(UINT32_MAX),
+                      GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                      0,
+                      StreamRotation::ROTATION_0};
+            streams[0] = stream3_2;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                    &config3_2, &config3_4);
+            if(session3_4 != nullptr) {
+                ret = session3_4->configureStreams_3_4(config3_4,
+                        [](Status s, device::V3_4::HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            } else if(session3_3 != nullptr) {
+                ret = session3_3->configureStreams_3_3(config3_2,
+                        [](Status s, device::V3_3::HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            } else {
+                ret = session->configureStreams(config3_2,
+                        [](Status s, HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            }
+            ASSERT_TRUE(ret.isOk());
+
+            stream3_2 = {streamId++,
+                      StreamType::OUTPUT,
+                      static_cast<uint32_t>(it.width),
+                      static_cast<uint32_t>(it.height),
+                      static_cast<PixelFormat>(it.format),
+                      GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                      0,
+                      static_cast<StreamRotation>(UINT32_MAX)};
+            streams[0] = stream3_2;
+            createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                    &config3_2, &config3_4);
+            if(session3_4 != nullptr) {
+                ret = session3_4->configureStreams_3_4(config3_4,
+                        [](Status s, device::V3_4::HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            } else if(session3_3 != nullptr) {
+                ret = session3_3->configureStreams_3_3(config3_2,
+                        [](Status s, device::V3_3::HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            } else {
+                ret = session->configureStreams(config3_2,
+                        [](Status s, HalStreamConfiguration) {
+                            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                        });
+            }
+            ASSERT_TRUE(ret.isOk());
+        }
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2509,107 +2615,211 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
 
-                Status rc = isZSLModeAvailable(staticMeta);
-                if (Status::METHOD_NOT_SUPPORTED == rc) {
-                    ret = session->close();
-                    ASSERT_TRUE(ret.isOk());
-                    continue;
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
+
+        Status rc = isZSLModeAvailable(staticMeta);
+        if (Status::METHOD_NOT_SUPPORTED == rc) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        ASSERT_EQ(Status::OK, rc);
+
+        inputStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, inputStreams));
+        ASSERT_NE(0u, inputStreams.size());
+
+        inputOutputMap.clear();
+        ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, inputOutputMap));
+        ASSERT_NE(0u, inputOutputMap.size());
+
+        int32_t streamId = 0;
+        for (auto& inputIter : inputOutputMap) {
+            AvailableStream input;
+            ASSERT_EQ(Status::OK, findLargestSize(inputStreams, inputIter.inputFormat,
+                    input));
+            ASSERT_NE(0u, inputStreams.size());
+
+            AvailableStream outputThreshold = {INT32_MAX, INT32_MAX,
+                                               inputIter.outputFormat};
+            std::vector<AvailableStream> outputStreams;
+            ASSERT_EQ(Status::OK,
+                      getAvailableOutputStreams(staticMeta, outputStreams,
+                              &outputThreshold));
+            for (auto& outputIter : outputStreams) {
+                V3_2::Stream zslStream = {streamId++,
+                                    StreamType::OUTPUT,
+                                    static_cast<uint32_t>(input.width),
+                                    static_cast<uint32_t>(input.height),
+                                    static_cast<PixelFormat>(input.format),
+                                    GRALLOC_USAGE_HW_CAMERA_ZSL,
+                                    0,
+                                    StreamRotation::ROTATION_0};
+                V3_2::Stream inputStream = {streamId++,
+                                      StreamType::INPUT,
+                                      static_cast<uint32_t>(input.width),
+                                      static_cast<uint32_t>(input.height),
+                                      static_cast<PixelFormat>(input.format),
+                                      0,
+                                      0,
+                                      StreamRotation::ROTATION_0};
+                V3_2::Stream outputStream = {streamId++,
+                                       StreamType::OUTPUT,
+                                       static_cast<uint32_t>(outputIter.width),
+                                       static_cast<uint32_t>(outputIter.height),
+                                       static_cast<PixelFormat>(outputIter.format),
+                                       GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                                       0,
+                                       StreamRotation::ROTATION_0};
+
+                ::android::hardware::hidl_vec<V3_2::Stream> streams = {inputStream, zslStream,
+                                                                 outputStream};
+                ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+                ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+                createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                                          &config3_2, &config3_4);
+                if (session3_4 != nullptr) {
+                    ret = session3_4->configureStreams_3_4(config3_4,
+                            [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(3u, halConfig.streams.size());
+                            });
+                } else if (session3_3 != nullptr) {
+                    ret = session3_3->configureStreams_3_3(config3_2,
+                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(3u, halConfig.streams.size());
+                            });
+                } else {
+                    ret = session->configureStreams(config3_2,
+                            [](Status s, HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(3u, halConfig.streams.size());
+                            });
                 }
-                ASSERT_EQ(Status::OK, rc);
-
-                inputStreams.clear();
-                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, inputStreams));
-                ASSERT_NE(0u, inputStreams.size());
-
-                inputOutputMap.clear();
-                ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta, inputOutputMap));
-                ASSERT_NE(0u, inputOutputMap.size());
-
-                int32_t streamId = 0;
-                for (auto& inputIter : inputOutputMap) {
-                    AvailableStream input;
-                    ASSERT_EQ(Status::OK, findLargestSize(inputStreams, inputIter.inputFormat,
-                            input));
-                    ASSERT_NE(0u, inputStreams.size());
-
-                    AvailableStream outputThreshold = {INT32_MAX, INT32_MAX,
-                                                       inputIter.outputFormat};
-                    std::vector<AvailableStream> outputStreams;
-                    ASSERT_EQ(Status::OK,
-                              getAvailableOutputStreams(staticMeta, outputStreams,
-                                      &outputThreshold));
-                    for (auto& outputIter : outputStreams) {
-                        Stream zslStream = {streamId++,
-                                            StreamType::OUTPUT,
-                                            static_cast<uint32_t>(input.width),
-                                            static_cast<uint32_t>(input.height),
-                                            static_cast<PixelFormat>(input.format),
-                                            GRALLOC_USAGE_HW_CAMERA_ZSL,
-                                            0,
-                                            StreamRotation::ROTATION_0};
-                        Stream inputStream = {streamId++,
-                                              StreamType::INPUT,
-                                              static_cast<uint32_t>(input.width),
-                                              static_cast<uint32_t>(input.height),
-                                              static_cast<PixelFormat>(input.format),
-                                              0,
-                                              0,
-                                              StreamRotation::ROTATION_0};
-                        Stream outputStream = {streamId++,
-                                               StreamType::OUTPUT,
-                                               static_cast<uint32_t>(outputIter.width),
-                                               static_cast<uint32_t>(outputIter.height),
-                                               static_cast<PixelFormat>(outputIter.format),
-                                               GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                                               0,
-                                               StreamRotation::ROTATION_0};
-
-                        ::android::hardware::hidl_vec<Stream> streams = {inputStream, zslStream,
-                                                                         outputStream};
-                        StreamConfiguration config = {streams,
-                                                      StreamConfigurationMode::NORMAL_MODE};
-                        if (session3_3 == nullptr) {
-                            ret = session->configureStreams(config,
-                                    [](Status s, HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(3u, halConfig.streams.size());
-                                    });
-                        } else {
-                            ret = session3_3->configureStreams_3_3(config,
-                                    [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(3u, halConfig.streams.size());
-                                    });
-                        }
-                        ASSERT_TRUE(ret.isOk());
-                    }
-                }
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
                 ASSERT_TRUE(ret.isOk());
             }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
         }
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Check wehether session parameters are supported. If Hal support for them
+// exist, then try to configure a preview stream using them.
+TEST_F(CameraHidlTest, configureStreamsWithSessionParameters) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    std::vector<AvailableStream> outputPreviewStreams;
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+
+    for (const auto& name : cameraDeviceNames) {
+        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+        if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        } else if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
+            continue;
+        }
+
+        camera_metadata_t* staticMetaBuffer;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
+        ASSERT_NE(session3_4, nullptr);
+
+        const android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta(
+                staticMetaBuffer);
+        camera_metadata_ro_entry availableSessionKeys = staticMeta.find(
+                ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
+        if (availableSessionKeys.count == 0) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        android::hardware::camera::common::V1_0::helper::CameraMetadata previewRequestSettings;
+        ret = session->constructDefaultRequestSettings(RequestTemplate::PREVIEW,
+                [&previewRequestSettings] (auto status, const auto& req) mutable {
+                    ASSERT_EQ(Status::OK, status);
+
+                    const camera_metadata_t *metadata = reinterpret_cast<const camera_metadata_t*> (
+                            req.data());
+                    size_t expectedSize = req.size();
+                    int result = validate_camera_metadata_structure(metadata, &expectedSize);
+                    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+
+                    size_t entryCount = get_camera_metadata_entry_count(metadata);
+                    ASSERT_GT(entryCount, 0u);
+                    previewRequestSettings = metadata;
+                    });
+        ASSERT_TRUE(ret.isOk());
+        const android::hardware::camera::common::V1_0::helper::CameraMetadata &constSettings =
+            previewRequestSettings;
+        android::hardware::camera::common::V1_0::helper::CameraMetadata sessionParams;
+        for (size_t i = 0; i < availableSessionKeys.count; i++) {
+            camera_metadata_ro_entry entry = constSettings.find(availableSessionKeys.data.i32[i]);
+            if (entry.count > 0) {
+                sessionParams.update(entry);
+            }
+        }
+        if (sessionParams.isEmpty()) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMetaBuffer, outputPreviewStreams,
+                &previewThreshold));
+        ASSERT_NE(0u, outputPreviewStreams.size());
+
+        V3_4::Stream previewStream;
+        previewStream.v3_2 = {0,
+                                StreamType::OUTPUT,
+                                static_cast<uint32_t>(outputPreviewStreams[0].width),
+                                static_cast<uint32_t>(outputPreviewStreams[0].height),
+                                static_cast<PixelFormat>(outputPreviewStreams[0].format),
+                                GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                                0,
+                                StreamRotation::ROTATION_0};
+        ::android::hardware::hidl_vec<V3_4::Stream> streams = {previewStream};
+        ::android::hardware::camera::device::V3_4::StreamConfiguration config;
+        config.streams = streams;
+        config.operationMode = StreamConfigurationMode::NORMAL_MODE;
+        const camera_metadata_t *sessionParamsBuffer = sessionParams.getAndLock();
+        config.sessionParams.setToExternal(
+                reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (sessionParamsBuffer)),
+                get_camera_metadata_size(sessionParamsBuffer));
+        ret = session3_4->configureStreams_3_4(config,
+                [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                    ASSERT_EQ(Status::OK, s);
+                    ASSERT_EQ(1u, halConfig.streams.size());
+                });
+        ASSERT_TRUE(ret.isOk());
+
+        sessionParams.unlock(sessionParamsBuffer);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2626,82 +2836,84 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
 
-                outputBlobStreams.clear();
-                ASSERT_EQ(Status::OK,
-                          getAvailableOutputStreams(staticMeta, outputBlobStreams,
-                                  &blobThreshold));
-                ASSERT_NE(0u, outputBlobStreams.size());
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
 
-                outputPreviewStreams.clear();
-                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputPreviewStreams,
-                        &previewThreshold));
-                ASSERT_NE(0u, outputPreviewStreams.size());
+        outputBlobStreams.clear();
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputBlobStreams,
+                          &blobThreshold));
+        ASSERT_NE(0u, outputBlobStreams.size());
 
-                int32_t streamId = 0;
-                for (auto& blobIter : outputBlobStreams) {
-                    for (auto& previewIter : outputPreviewStreams) {
-                        Stream previewStream = {streamId++,
-                                                StreamType::OUTPUT,
-                                                static_cast<uint32_t>(previewIter.width),
-                                                static_cast<uint32_t>(previewIter.height),
-                                                static_cast<PixelFormat>(previewIter.format),
-                                                GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
-                                                0,
-                                                StreamRotation::ROTATION_0};
-                        Stream blobStream = {streamId++,
-                                             StreamType::OUTPUT,
-                                             static_cast<uint32_t>(blobIter.width),
-                                             static_cast<uint32_t>(blobIter.height),
-                                             static_cast<PixelFormat>(blobIter.format),
-                                             GRALLOC1_CONSUMER_USAGE_CPU_READ,
-                                             0,
-                                             StreamRotation::ROTATION_0};
-                        ::android::hardware::hidl_vec<Stream> streams = {previewStream,
-                                                                         blobStream};
-                        StreamConfiguration config = {streams,
-                                                      StreamConfigurationMode::NORMAL_MODE};
-                        if (session3_3 == nullptr) {
-                            ret = session->configureStreams(config,
-                                    [](Status s, HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(2u, halConfig.streams.size());
-                                    });
-                        } else {
-                            ret = session3_3->configureStreams_3_3(config,
-                                    [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(2u, halConfig.streams.size());
-                                    });
-                        }
-                        ASSERT_TRUE(ret.isOk());
-                    }
+        outputPreviewStreams.clear();
+        ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputPreviewStreams,
+                &previewThreshold));
+        ASSERT_NE(0u, outputPreviewStreams.size());
+
+        int32_t streamId = 0;
+        for (auto& blobIter : outputBlobStreams) {
+            for (auto& previewIter : outputPreviewStreams) {
+                V3_2::Stream previewStream = {streamId++,
+                                        StreamType::OUTPUT,
+                                        static_cast<uint32_t>(previewIter.width),
+                                        static_cast<uint32_t>(previewIter.height),
+                                        static_cast<PixelFormat>(previewIter.format),
+                                        GRALLOC1_CONSUMER_USAGE_HWCOMPOSER,
+                                        0,
+                                        StreamRotation::ROTATION_0};
+                V3_2::Stream blobStream = {streamId++,
+                                     StreamType::OUTPUT,
+                                     static_cast<uint32_t>(blobIter.width),
+                                     static_cast<uint32_t>(blobIter.height),
+                                     static_cast<PixelFormat>(blobIter.format),
+                                     GRALLOC1_CONSUMER_USAGE_CPU_READ,
+                                     0,
+                                     StreamRotation::ROTATION_0};
+                ::android::hardware::hidl_vec<V3_2::Stream> streams = {previewStream,
+                                                                 blobStream};
+                ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+                ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+                createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                                          &config3_2, &config3_4);
+                if (session3_4 != nullptr) {
+                    ret = session3_4->configureStreams_3_4(config3_4,
+                            [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
+                } else if (session3_3 != nullptr) {
+                    ret = session3_3->configureStreams_3_3(config3_2,
+                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
+                } else {
+                    ret = session->configureStreams(config3_2,
+                            [](Status s, HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
                 }
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
                 ASSERT_TRUE(ret.isOk());
             }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
         }
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2713,143 +2925,165 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
-
-                Status rc = isConstrainedModeAvailable(staticMeta);
-                if (Status::METHOD_NOT_SUPPORTED == rc) {
-                    ret = session->close();
-                    ASSERT_TRUE(ret.isOk());
-                    continue;
-                }
-                ASSERT_EQ(Status::OK, rc);
-
-                AvailableStream hfrStream;
-                rc = pickConstrainedModeSize(staticMeta, hfrStream);
-                ASSERT_EQ(Status::OK, rc);
-
-                int32_t streamId = 0;
-                Stream stream = {streamId,
-                                 StreamType::OUTPUT,
-                                 static_cast<uint32_t>(hfrStream.width),
-                                 static_cast<uint32_t>(hfrStream.height),
-                                 static_cast<PixelFormat>(hfrStream.format),
-                                 GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
-                                 0,
-                                 StreamRotation::ROTATION_0};
-                ::android::hardware::hidl_vec<Stream> streams = {stream};
-                StreamConfiguration config = {streams,
-                                              StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-                if (session3_3 == nullptr) {
-                    ret = session->configureStreams(config,
-                            [streamId](Status s, HalStreamConfiguration halConfig) {
-                                ASSERT_EQ(Status::OK, s);
-                                ASSERT_EQ(1u, halConfig.streams.size());
-                                ASSERT_EQ(halConfig.streams[0].id, streamId);
-                            });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config,
-                            [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
-                                ASSERT_EQ(Status::OK, s);
-                                ASSERT_EQ(1u, halConfig.streams.size());
-                                ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
-                            });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                stream = {streamId++,
-                          StreamType::OUTPUT,
-                          static_cast<uint32_t>(0),
-                          static_cast<uint32_t>(0),
-                          static_cast<PixelFormat>(hfrStream.format),
-                          GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
-                          0,
-                          StreamRotation::ROTATION_0};
-                streams[0] = stream;
-                config = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-                if (session3_3 == nullptr) {
-                    ret = session->configureStreams(config,
-                            [](Status s, HalStreamConfiguration) {
-                                ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                                        (Status::INTERNAL_ERROR == s));
-                            });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config,
-                            [](Status s, device::V3_3::HalStreamConfiguration) {
-                                ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                                        (Status::INTERNAL_ERROR == s));
-                            });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                stream = {streamId++,
-                          StreamType::OUTPUT,
-                          static_cast<uint32_t>(UINT32_MAX),
-                          static_cast<uint32_t>(UINT32_MAX),
-                          static_cast<PixelFormat>(hfrStream.format),
-                          GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
-                          0,
-                          StreamRotation::ROTATION_0};
-                streams[0] = stream;
-                config = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-                if (session3_3 == nullptr) {
-                    ret = session->configureStreams(config,
-                            [](Status s, HalStreamConfiguration) {
-                                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                            });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config,
-                            [](Status s, device::V3_3::HalStreamConfiguration) {
-                                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                            });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                stream = {streamId++,
-                          StreamType::OUTPUT,
-                          static_cast<uint32_t>(hfrStream.width),
-                          static_cast<uint32_t>(hfrStream.height),
-                          static_cast<PixelFormat>(UINT32_MAX),
-                          GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
-                          0,
-                          StreamRotation::ROTATION_0};
-                streams[0] = stream;
-                config = {streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-                if (session3_3 == nullptr) {
-                    ret = session->configureStreams(config,
-                            [](Status s, HalStreamConfiguration) {
-                                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                            });
-                } else {
-                    ret = session3_3->configureStreams_3_3(config,
-                            [](Status s, device::V3_3::HalStreamConfiguration) {
-                                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                            });
-                }
-                ASSERT_TRUE(ret.isOk());
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
+
+        Status rc = isConstrainedModeAvailable(staticMeta);
+        if (Status::METHOD_NOT_SUPPORTED == rc) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        ASSERT_EQ(Status::OK, rc);
+
+        AvailableStream hfrStream;
+        rc = pickConstrainedModeSize(staticMeta, hfrStream);
+        ASSERT_EQ(Status::OK, rc);
+
+        int32_t streamId = 0;
+        V3_2::Stream stream = {streamId,
+                         StreamType::OUTPUT,
+                         static_cast<uint32_t>(hfrStream.width),
+                         static_cast<uint32_t>(hfrStream.height),
+                         static_cast<PixelFormat>(hfrStream.format),
+                         GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
+                         0,
+                         StreamRotation::ROTATION_0};
+        ::android::hardware::hidl_vec<V3_2::Stream> streams = {stream};
+        ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+        ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config3_2, &config3_4);
+        if (session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                    [streamId](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                        ASSERT_EQ(Status::OK, s);
+                        ASSERT_EQ(1u, halConfig.streams.size());
+                        ASSERT_EQ(halConfig.streams[0].v3_3.v3_2.id, streamId);
+                    });
+        } else if (session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config3_2,
+                    [streamId](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                        ASSERT_EQ(Status::OK, s);
+                        ASSERT_EQ(1u, halConfig.streams.size());
+                        ASSERT_EQ(halConfig.streams[0].v3_2.id, streamId);
+                    });
+        } else {
+            ret = session->configureStreams(config3_2,
+                    [streamId](Status s, HalStreamConfiguration halConfig) {
+                        ASSERT_EQ(Status::OK, s);
+                        ASSERT_EQ(1u, halConfig.streams.size());
+                        ASSERT_EQ(halConfig.streams[0].id, streamId);
+                    });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  static_cast<uint32_t>(0),
+                  static_cast<uint32_t>(0),
+                  static_cast<PixelFormat>(hfrStream.format),
+                  GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
+                  0,
+                  StreamRotation::ROTATION_0};
+        streams[0] = stream;
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config3_2, &config3_4);
+        if (session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                    });
+        } else if (session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config3_2,
+                    [](Status s, device::V3_3::HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                    });
+        } else {
+            ret = session->configureStreams(config3_2,
+                    [](Status s, HalStreamConfiguration) {
+                        ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                    });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  static_cast<uint32_t>(UINT32_MAX),
+                  static_cast<uint32_t>(UINT32_MAX),
+                  static_cast<PixelFormat>(hfrStream.format),
+                  GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
+                  0,
+                  StreamRotation::ROTATION_0};
+        streams[0] = stream;
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config3_2, &config3_4);
+        if (session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        } else if (session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config3_2,
+                    [](Status s, device::V3_3::HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        } else {
+            ret = session->configureStreams(config3_2,
+                    [](Status s, HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        stream = {streamId++,
+                  StreamType::OUTPUT,
+                  static_cast<uint32_t>(hfrStream.width),
+                  static_cast<uint32_t>(hfrStream.height),
+                  static_cast<PixelFormat>(UINT32_MAX),
+                  GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
+                  0,
+                  StreamRotation::ROTATION_0};
+        streams[0] = stream;
+        createStreamConfiguration(streams, StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE,
+                                  &config3_2, &config3_4);
+        if (session3_4 != nullptr) {
+            ret = session3_4->configureStreams_3_4(config3_4,
+                    [](Status s, device::V3_4::HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        } else if (session3_3 != nullptr) {
+            ret = session3_3->configureStreams_3_3(config3_2,
+                    [](Status s, device::V3_3::HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        } else {
+            ret = session->configureStreams(config3_2,
+                    [](Status s, HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+        }
+        ASSERT_TRUE(ret.isOk());
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2866,82 +3100,84 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                camera_metadata_t* staticMeta;
-                Return<void> ret;
-                sp<ICameraDeviceSession> session;
-                sp<device::V3_3::ICameraDeviceSession> session3_3;
-                openEmptyDeviceSession(name, mProvider,
-                        &session /*out*/, &session3_3 /*out*/, &staticMeta /*out*/);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
 
-                outputBlobStreams.clear();
-                ASSERT_EQ(Status::OK,
-                          getAvailableOutputStreams(staticMeta, outputBlobStreams,
-                                  &blobThreshold));
-                ASSERT_NE(0u, outputBlobStreams.size());
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        sp<device::V3_3::ICameraDeviceSession> session3_3;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+        castSession(session, deviceVersion, &session3_3, &session3_4);
 
-                outputVideoStreams.clear();
-                ASSERT_EQ(Status::OK,
-                          getAvailableOutputStreams(staticMeta, outputVideoStreams,
-                                  &videoThreshold));
-                ASSERT_NE(0u, outputVideoStreams.size());
+        outputBlobStreams.clear();
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputBlobStreams,
+                          &blobThreshold));
+        ASSERT_NE(0u, outputBlobStreams.size());
 
-                int32_t streamId = 0;
-                for (auto& blobIter : outputBlobStreams) {
-                    for (auto& videoIter : outputVideoStreams) {
-                        Stream videoStream = {streamId++,
-                                              StreamType::OUTPUT,
-                                              static_cast<uint32_t>(videoIter.width),
-                                              static_cast<uint32_t>(videoIter.height),
-                                              static_cast<PixelFormat>(videoIter.format),
-                                              GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
-                                              0,
-                                              StreamRotation::ROTATION_0};
-                        Stream blobStream = {streamId++,
-                                             StreamType::OUTPUT,
-                                             static_cast<uint32_t>(blobIter.width),
-                                             static_cast<uint32_t>(blobIter.height),
-                                             static_cast<PixelFormat>(blobIter.format),
-                                             GRALLOC1_CONSUMER_USAGE_CPU_READ,
-                                             0,
-                                             StreamRotation::ROTATION_0};
-                        ::android::hardware::hidl_vec<Stream> streams = {videoStream, blobStream};
-                        StreamConfiguration config = {streams,
-                                                      StreamConfigurationMode::NORMAL_MODE};
-                        if (session3_3 == nullptr) {
-                            ret = session->configureStreams(config,
-                                    [](Status s, HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(2u, halConfig.streams.size());
-                                    });
-                        } else {
-                            ret = session3_3->configureStreams_3_3(config,
-                                    [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
-                                        ASSERT_EQ(Status::OK, s);
-                                        ASSERT_EQ(2u, halConfig.streams.size());
-                                    });
-                        }
-                        ASSERT_TRUE(ret.isOk());
-                    }
+        outputVideoStreams.clear();
+        ASSERT_EQ(Status::OK,
+                  getAvailableOutputStreams(staticMeta, outputVideoStreams,
+                          &videoThreshold));
+        ASSERT_NE(0u, outputVideoStreams.size());
+
+        int32_t streamId = 0;
+        for (auto& blobIter : outputBlobStreams) {
+            for (auto& videoIter : outputVideoStreams) {
+                V3_2::Stream videoStream = {streamId++,
+                                      StreamType::OUTPUT,
+                                      static_cast<uint32_t>(videoIter.width),
+                                      static_cast<uint32_t>(videoIter.height),
+                                      static_cast<PixelFormat>(videoIter.format),
+                                      GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER,
+                                      0,
+                                      StreamRotation::ROTATION_0};
+                V3_2::Stream blobStream = {streamId++,
+                                     StreamType::OUTPUT,
+                                     static_cast<uint32_t>(blobIter.width),
+                                     static_cast<uint32_t>(blobIter.height),
+                                     static_cast<PixelFormat>(blobIter.format),
+                                     GRALLOC1_CONSUMER_USAGE_CPU_READ,
+                                     0,
+                                     StreamRotation::ROTATION_0};
+                ::android::hardware::hidl_vec<V3_2::Stream> streams = {videoStream, blobStream};
+                ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+                ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+                createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE,
+                                          &config3_2, &config3_4);
+                if (session3_4 != nullptr) {
+                    ret = session3_4->configureStreams_3_4(config3_4,
+                            [](Status s, device::V3_4::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
+                } else if (session3_3 != nullptr) {
+                    ret = session3_3->configureStreams_3_3(config3_2,
+                            [](Status s, device::V3_3::HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
+                } else {
+                    ret = session->configureStreams(config3_2,
+                            [](Status s, HalStreamConfiguration halConfig) {
+                                ASSERT_EQ(Status::OK, s);
+                                ASSERT_EQ(2u, halConfig.streams.size());
+                            });
                 }
-
-                free_camera_metadata(staticMeta);
-                ret = session->close();
                 ASSERT_TRUE(ret.isOk());
             }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
         }
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -2956,152 +3192,312 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                Stream previewStream;
-                HalStreamConfiguration halStreamConfig;
-                sp<ICameraDeviceSession> session;
-                bool supportsPartialResults = false;
-                uint32_t partialResultCount = 0;
-                configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/,
-                                       &previewStream /*out*/, &halStreamConfig /*out*/,
-                                       &supportsPartialResults /*out*/,
-                                       &partialResultCount /*out*/);
-
-                std::shared_ptr<ResultMetadataQueue> resultQueue;
-                auto resultQueueRet =
-                    session->getCaptureResultMetadataQueue(
-                        [&resultQueue](const auto& descriptor) {
-                            resultQueue = std::make_shared<ResultMetadataQueue>(
-                                    descriptor);
-                            if (!resultQueue->isValid() ||
-                                    resultQueue->availableToWrite() <= 0) {
-                                ALOGE("%s: HAL returns empty result metadata fmq,"
-                                        " not use it", __func__);
-                                resultQueue = nullptr;
-                                // Don't use the queue onwards.
-                            }
-                        });
-                ASSERT_TRUE(resultQueueRet.isOk());
-
-                InFlightRequest inflightReq = {1, false, supportsPartialResults,
-                                               partialResultCount, resultQueue};
-
-                RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
-                Return<void> ret;
-                ret = session->constructDefaultRequestSettings(reqTemplate,
-                                                               [&](auto status, const auto& req) {
-                                                                   ASSERT_EQ(Status::OK, status);
-                                                                   settings = req;
-                                                               });
-                ASSERT_TRUE(ret.isOk());
-
-                sp<GraphicBuffer> gb = new GraphicBuffer(
-                    previewStream.width, previewStream.height,
-                    static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
-                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                                                    halStreamConfig.streams[0].consumerUsage));
-                ASSERT_NE(nullptr, gb.get());
-                StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
-                                             bufferId,
-                                             hidl_handle(gb->getNativeBuffer()->handle),
-                                             BufferStatus::OK,
-                                             nullptr,
-                                             nullptr};
-                ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
-                StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
-                                                 nullptr};
-                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                                          emptyInputBuffer, outputBuffers};
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    mInflightMap.clear();
-                    mInflightMap.add(frameNumber, &inflightReq);
-                }
-
-                Status status = Status::INTERNAL_ERROR;
-                uint32_t numRequestProcessed = 0;
-                hidl_vec<BufferCache> cachesToRemove;
-                Return<void> returnStatus = session->processCaptureRequest(
-                    {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
-                            uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, status);
-                ASSERT_EQ(numRequestProcessed, 1u);
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    while (!inflightReq.errorCodeValid &&
-                           ((0 < inflightReq.numBuffersLeft) ||
-                                   (!inflightReq.haveResultMetadata))) {
-                        auto timeout = std::chrono::system_clock::now() +
-                                       std::chrono::seconds(kStreamBufferTimeoutSec);
-                        ASSERT_NE(std::cv_status::timeout,
-                                mResultCondition.wait_until(l, timeout));
-                    }
-
-                    ASSERT_FALSE(inflightReq.errorCodeValid);
-                    ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                    ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
-
-                    request.frameNumber++;
-                    // Empty settings should be supported after the first call
-                    // for repeating requests.
-                    request.settings.setToExternal(nullptr, 0, true);
-                    // The buffer has been registered to HAL by bufferId, so per
-                    // API contract we should send a null handle for this buffer
-                    request.outputBuffers[0].buffer = nullptr;
-                    mInflightMap.clear();
-                    inflightReq = {1, false, supportsPartialResults, partialResultCount,
-                                   resultQueue};
-                    mInflightMap.add(request.frameNumber, &inflightReq);
-                }
-
-                returnStatus = session->processCaptureRequest(
-                    {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
-                            uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, status);
-                ASSERT_EQ(numRequestProcessed, 1u);
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    while (!inflightReq.errorCodeValid &&
-                           ((0 < inflightReq.numBuffersLeft) ||
-                                   (!inflightReq.haveResultMetadata))) {
-                        auto timeout = std::chrono::system_clock::now() +
-                                       std::chrono::seconds(kStreamBufferTimeoutSec);
-                        ASSERT_NE(std::cv_status::timeout,
-                                mResultCondition.wait_until(l, timeout));
-                    }
-
-                    ASSERT_FALSE(inflightReq.errorCodeValid);
-                    ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                    ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
-                }
-
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        V3_2::Stream previewStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
+                &previewStream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/,
+                &partialResultCount /*out*/);
+
+        std::shared_ptr<ResultMetadataQueue> resultQueue;
+        auto resultQueueRet =
+            session->getCaptureResultMetadataQueue(
+                [&resultQueue](const auto& descriptor) {
+                    resultQueue = std::make_shared<ResultMetadataQueue>(
+                            descriptor);
+                    if (!resultQueue->isValid() ||
+                            resultQueue->availableToWrite() <= 0) {
+                        ALOGE("%s: HAL returns empty result metadata fmq,"
+                                " not use it", __func__);
+                        resultQueue = nullptr;
+                        // Don't use the queue onwards.
+                    }
+                });
+        ASSERT_TRUE(resultQueueRet.isOk());
+
+        InFlightRequest inflightReq = {1, false, supportsPartialResults,
+                                       partialResultCount, resultQueue};
+
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+        Return<void> ret;
+        ret = session->constructDefaultRequestSettings(reqTemplate,
+                                                       [&](auto status, const auto& req) {
+                                                           ASSERT_EQ(Status::OK, status);
+                                                           settings = req;
+                                                       });
+        ASSERT_TRUE(ret.isOk());
+
+        sp<GraphicBuffer> gb = new GraphicBuffer(
+            previewStream.width, previewStream.height,
+            static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
+            android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                                            halStreamConfig.streams[0].consumerUsage));
+        ASSERT_NE(nullptr, gb.get());
+        StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+                                     bufferId,
+                                     hidl_handle(gb->getNativeBuffer()->handle),
+                                     BufferStatus::OK,
+                                     nullptr,
+                                     nullptr};
+        ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
+                                         nullptr};
+        CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
+                                  emptyInputBuffer, outputBuffers};
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            mInflightMap.clear();
+            mInflightMap.add(frameNumber, &inflightReq);
+        }
+
+        Status status = Status::INTERNAL_ERROR;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        Return<void> returnStatus = session->processCaptureRequest(
+            {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
+                    uint32_t n) {
+                status = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq.errorCodeValid &&
+                   ((0 < inflightReq.numBuffersLeft) ||
+                           (!inflightReq.haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout,
+                        mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq.errorCodeValid);
+            ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+
+            request.frameNumber++;
+            // Empty settings should be supported after the first call
+            // for repeating requests.
+            request.settings.setToExternal(nullptr, 0, true);
+            // The buffer has been registered to HAL by bufferId, so per
+            // API contract we should send a null handle for this buffer
+            request.outputBuffers[0].buffer = nullptr;
+            mInflightMap.clear();
+            inflightReq = {1, false, supportsPartialResults, partialResultCount,
+                           resultQueue};
+            mInflightMap.add(request.frameNumber, &inflightReq);
+        }
+
+        returnStatus = session->processCaptureRequest(
+            {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
+                    uint32_t n) {
+                status = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq.errorCodeValid &&
+                   ((0 < inflightReq.numBuffersLeft) ||
+                           (!inflightReq.haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout,
+                        mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq.errorCodeValid);
+            ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+            ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+        }
+
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+// Generate and verify a multi-camera capture request
+TEST_F(CameraHidlTest, processMultiCaptureRequestPreview) {
+    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                                        static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
+    uint64_t bufferId = 1;
+    uint32_t frameNumber = 1;
+    ::android::hardware::hidl_vec<uint8_t> settings;
+    ::android::hardware::hidl_vec<uint8_t> emptySettings;
+    hidl_string invalidPhysicalId = "-1";
+
+    for (const auto& name : cameraDeviceNames) {
+        int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+        if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
+            continue;
+        }
+        camera_metadata_t* staticMeta;
+        Return<void> ret;
+        sp<ICameraDeviceSession> session;
+        openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/);
+
+        Status rc = isLogicalMultiCamera(staticMeta);
+        if (Status::METHOD_NOT_SUPPORTED == rc) {
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
+            continue;
+        }
+        std::unordered_set<std::string> physicalIds;
+        rc = getPhysicalCameraIds(staticMeta, &physicalIds);
+        ASSERT_TRUE(Status::OK == rc);
+        ASSERT_TRUE(physicalIds.size() > 1);
+
+        free_camera_metadata(staticMeta);
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
+
+        // Leave only 2 physical devices in the id set.
+        auto it = physicalIds.begin(); it++; it++;
+        physicalIds.erase(it, physicalIds.end());
+
+        V3_4::HalStreamConfiguration halStreamConfig;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        V3_2::Stream previewStream;
+        sp<device::V3_4::ICameraDeviceSession> session3_4;
+        configurePreviewStreams3_4(name, deviceVersion, mProvider, &previewThreshold, physicalIds,
+                &session3_4, &previewStream, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/, &partialResultCount /*out*/);
+        ASSERT_NE(session3_4, nullptr);
+
+        std::shared_ptr<ResultMetadataQueue> resultQueue;
+        auto resultQueueRet =
+            session3_4->getCaptureResultMetadataQueue(
+                [&resultQueue](const auto& descriptor) {
+                    resultQueue = std::make_shared<ResultMetadataQueue>(
+                            descriptor);
+                    if (!resultQueue->isValid() ||
+                            resultQueue->availableToWrite() <= 0) {
+                        ALOGE("%s: HAL returns empty result metadata fmq,"
+                                " not use it", __func__);
+                        resultQueue = nullptr;
+                        // Don't use the queue onwards.
+                    }
+                });
+        ASSERT_TRUE(resultQueueRet.isOk());
+
+        InFlightRequest inflightReq = {static_cast<ssize_t> (physicalIds.size()), false,
+            supportsPartialResults, partialResultCount, resultQueue};
+
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+        ret = session3_4->constructDefaultRequestSettings(reqTemplate,
+                                                       [&](auto status, const auto& req) {
+                                                           ASSERT_EQ(Status::OK, status);
+                                                           settings = req;
+                                                       });
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_TRUE(settings.size() > 0);
+
+        std::vector<sp<GraphicBuffer>> graphicBuffers;
+        graphicBuffers.reserve(physicalIds.size());
+        ::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
+        outputBuffers.resize(physicalIds.size());
+        hidl_vec<V3_4::PhysicalCameraSetting> camSettings;
+        camSettings.resize(physicalIds.size());
+        size_t k = 0;
+        for (const auto physicalIdIt : physicalIds) {
+            sp<GraphicBuffer> gb = new GraphicBuffer(previewStream.width, previewStream.height,
+                    static_cast<int32_t>(halStreamConfig.streams[k].v3_3.v3_2.overrideFormat), 1,
+                    android_convertGralloc1To0Usage(
+                        halStreamConfig.streams[k].v3_3.v3_2.producerUsage,
+                        halStreamConfig.streams[k].v3_3.v3_2.consumerUsage));
+            ASSERT_NE(nullptr, gb.get());
+            outputBuffers[k] = {halStreamConfig.streams[k].v3_3.v3_2.id, bufferId,
+                hidl_handle(gb->getNativeBuffer()->handle), BufferStatus::OK, nullptr, nullptr};
+            graphicBuffers.push_back(gb);
+            camSettings[k] = {0, hidl_string(physicalIdIt), settings};
+            k++;
+        }
+
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
+        V3_4::CaptureRequest request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
+                                  emptyInputBuffer, outputBuffers}, camSettings};
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            mInflightMap.clear();
+            mInflightMap.add(frameNumber, &inflightReq);
+        }
+
+        Status stat = Status::INTERNAL_ERROR;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        Return<void> returnStatus = session3_4->processCaptureRequest_3_4(
+            {request}, cachesToRemove, [&stat, &numRequestProcessed](auto s, uint32_t n) {
+                stat = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, stat);
+        ASSERT_EQ(numRequestProcessed, 1u);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq.errorCodeValid &&
+                    ((0 < inflightReq.numBuffersLeft) ||
+                     (!inflightReq.haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                    std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout,
+                        mResultCondition.wait_until(l, timeout));
+            }
+
+            ASSERT_FALSE(inflightReq.errorCodeValid);
+            ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+        }
+
+        // Empty physical camera settings should fail process requests
+        camSettings[1].settings = emptySettings;
+        frameNumber++;
+        request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
+            emptyInputBuffer, outputBuffers}, camSettings};
+        returnStatus = session3_4->processCaptureRequest_3_4(
+            {request}, cachesToRemove, [&stat, &numRequestProcessed](auto s, uint32_t n) {
+                stat = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
+
+        // Invalid physical camera id should fail process requests
+        camSettings[1].physicalCameraId = invalidPhysicalId;
+        camSettings[1].settings = settings;
+        request = {{frameNumber, 0 /* fmqSettingsSize */, settings,
+            emptyInputBuffer, outputBuffers}, camSettings};
+        returnStatus = session3_4->processCaptureRequest_3_4(
+            {request}, cachesToRemove, [&stat, &numRequestProcessed](auto s, uint32_t n) {
+                stat = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, stat);
+
+        ret = session3_4->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -3118,65 +3514,58 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                Stream previewStream;
-                HalStreamConfiguration halStreamConfig;
-                sp<ICameraDeviceSession> session;
-                bool supportsPartialResults = false;
-                uint32_t partialResultCount = 0;
-                configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/,
-                                       &previewStream /*out*/, &halStreamConfig /*out*/,
-                                       &supportsPartialResults /*out*/,
-                                       &partialResultCount /*out*/);
-
-                sp<GraphicBuffer> gb = new GraphicBuffer(
-                    previewStream.width, previewStream.height,
-                    static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
-                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                                                    halStreamConfig.streams[0].consumerUsage));
-
-                StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
-                                             bufferId,
-                                             hidl_handle(gb->getNativeBuffer()->handle),
-                                             BufferStatus::OK,
-                                             nullptr,
-                                             nullptr};
-                ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
-                StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
-                                                 nullptr};
-                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                                          emptyInputBuffer, outputBuffers};
-
-                // Settings were not correctly initialized, we should fail here
-                Status status = Status::OK;
-                uint32_t numRequestProcessed = 0;
-                hidl_vec<BufferCache> cachesToRemove;
-                Return<void> ret = session->processCaptureRequest(
-                    {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
-                            uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-                ASSERT_TRUE(ret.isOk());
-                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status);
-                ASSERT_EQ(numRequestProcessed, 0u);
-
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        V3_2::Stream previewStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
+                &previewStream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/,
+                &partialResultCount /*out*/);
+
+        sp<GraphicBuffer> gb = new GraphicBuffer(
+            previewStream.width, previewStream.height,
+            static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
+            android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                                            halStreamConfig.streams[0].consumerUsage));
+
+        StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+                                     bufferId,
+                                     hidl_handle(gb->getNativeBuffer()->handle),
+                                     BufferStatus::OK,
+                                     nullptr,
+                                     nullptr};
+        ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
+                                         nullptr};
+        CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
+                                  emptyInputBuffer, outputBuffers};
+
+        // Settings were not correctly initialized, we should fail here
+        Status status = Status::OK;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        Return<void> ret = session->processCaptureRequest(
+            {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
+                    uint32_t n) {
+                status = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status);
+        ASSERT_EQ(numRequestProcessed, 0u);
+
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -3192,62 +3581,55 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                Stream previewStream;
-                HalStreamConfiguration halStreamConfig;
-                sp<ICameraDeviceSession> session;
-                bool supportsPartialResults = false;
-                uint32_t partialResultCount = 0;
-                configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/,
-                                       &previewStream /*out*/, &halStreamConfig /*out*/,
-                                       &supportsPartialResults /*out*/,
-                                       &partialResultCount /*out*/);
-
-                RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
-                Return<void> ret;
-                ret = session->constructDefaultRequestSettings(reqTemplate,
-                                                               [&](auto status, const auto& req) {
-                                                                   ASSERT_EQ(Status::OK, status);
-                                                                   settings = req;
-                                                               });
-                ASSERT_TRUE(ret.isOk());
-
-                ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers;
-                StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
-                                                 nullptr};
-                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                                          emptyInputBuffer, emptyOutputBuffers};
-
-                // Output buffers are missing, we should fail here
-                Status status = Status::OK;
-                uint32_t numRequestProcessed = 0;
-                hidl_vec<BufferCache> cachesToRemove;
-                ret = session->processCaptureRequest(
-                    {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
-                            uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-                ASSERT_TRUE(ret.isOk());
-                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status);
-                ASSERT_EQ(numRequestProcessed, 0u);
-
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        V3_2::Stream previewStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
+                &previewStream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/,
+                &partialResultCount /*out*/);
+
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+        Return<void> ret;
+        ret = session->constructDefaultRequestSettings(reqTemplate,
+                                                       [&](auto status, const auto& req) {
+                                                           ASSERT_EQ(Status::OK, status);
+                                                           settings = req;
+                                                       });
+        ASSERT_TRUE(ret.isOk());
+
+        ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers;
+        StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr,
+                                         nullptr};
+        CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
+                                  emptyInputBuffer, emptyOutputBuffers};
+
+        // Output buffers are missing, we should fail here
+        Status status = Status::OK;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        ret = session->processCaptureRequest(
+            {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
+                    uint32_t n) {
+                status = s;
+                numRequestProcessed = n;
+            });
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status);
+        ASSERT_EQ(numRequestProcessed, 0u);
+
+        ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -3263,130 +3645,123 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                Stream previewStream;
-                HalStreamConfiguration halStreamConfig;
-                sp<ICameraDeviceSession> session;
-                bool supportsPartialResults = false;
-                uint32_t partialResultCount = 0;
-                configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/,
-                                       &previewStream /*out*/, &halStreamConfig /*out*/,
-                                       &supportsPartialResults /*out*/,
-                                       &partialResultCount /*out*/);
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
+        }
 
-                std::shared_ptr<ResultMetadataQueue> resultQueue;
-                auto resultQueueRet =
-                    session->getCaptureResultMetadataQueue(
-                        [&resultQueue](const auto& descriptor) {
-                            resultQueue = std::make_shared<ResultMetadataQueue>(
-                                    descriptor);
-                            if (!resultQueue->isValid() ||
-                                    resultQueue->availableToWrite() <= 0) {
-                                ALOGE("%s: HAL returns empty result metadata fmq,"
-                                        " not use it", __func__);
-                                resultQueue = nullptr;
-                                // Don't use the queue onwards.
-                            }
-                        });
-                ASSERT_TRUE(resultQueueRet.isOk());
+        V3_2::Stream previewStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
+                &previewStream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/,
+                &partialResultCount /*out*/);
 
-                InFlightRequest inflightReq = {1, false, supportsPartialResults,
-                                               partialResultCount, resultQueue};
-                RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
-                Return<void> ret;
-                ret = session->constructDefaultRequestSettings(reqTemplate,
-                                                               [&](auto status, const auto& req) {
-                                                                   ASSERT_EQ(Status::OK, status);
-                                                                   settings = req;
-                                                               });
-                ASSERT_TRUE(ret.isOk());
-
-                sp<GraphicBuffer> gb = new GraphicBuffer(
-                    previewStream.width, previewStream.height,
-                    static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
-                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                                                    halStreamConfig.streams[0].consumerUsage));
-                ASSERT_NE(nullptr, gb.get());
-                StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
-                                             bufferId,
-                                             hidl_handle(gb->getNativeBuffer()->handle),
-                                             BufferStatus::OK,
-                                             nullptr,
-                                             nullptr};
-                ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
-                const StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
-                                                       BufferStatus::ERROR, nullptr, nullptr};
-                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                                          emptyInputBuffer, outputBuffers};
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    mInflightMap.clear();
-                    mInflightMap.add(frameNumber, &inflightReq);
-                }
-
-                Status status = Status::INTERNAL_ERROR;
-                uint32_t numRequestProcessed = 0;
-                hidl_vec<BufferCache> cachesToRemove;
-                ret = session->processCaptureRequest(
-                    {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
-                            uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-
-                ASSERT_TRUE(ret.isOk());
-                ASSERT_EQ(Status::OK, status);
-                ASSERT_EQ(numRequestProcessed, 1u);
-                // Flush before waiting for request to complete.
-                Return<Status> returnStatus = session->flush();
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, returnStatus);
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    while (!inflightReq.errorCodeValid &&
-                           ((0 < inflightReq.numBuffersLeft) ||
-                                   (!inflightReq.haveResultMetadata))) {
-                        auto timeout = std::chrono::system_clock::now() +
-                                       std::chrono::seconds(kStreamBufferTimeoutSec);
-                        ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l,
-                                timeout));
+        std::shared_ptr<ResultMetadataQueue> resultQueue;
+        auto resultQueueRet =
+            session->getCaptureResultMetadataQueue(
+                [&resultQueue](const auto& descriptor) {
+                    resultQueue = std::make_shared<ResultMetadataQueue>(
+                            descriptor);
+                    if (!resultQueue->isValid() ||
+                            resultQueue->availableToWrite() <= 0) {
+                        ALOGE("%s: HAL returns empty result metadata fmq,"
+                                " not use it", __func__);
+                        resultQueue = nullptr;
+                        // Don't use the queue onwards.
                     }
+                });
+        ASSERT_TRUE(resultQueueRet.isOk());
 
-                    if (!inflightReq.errorCodeValid) {
-                        ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                        ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
-                    } else {
-                        switch (inflightReq.errorCode) {
-                            case ErrorCode::ERROR_REQUEST:
-                            case ErrorCode::ERROR_RESULT:
-                            case ErrorCode::ERROR_BUFFER:
-                                // Expected
-                                break;
-                            case ErrorCode::ERROR_DEVICE:
-                            default:
-                                FAIL() << "Unexpected error:"
-                                       << static_cast<uint32_t>(inflightReq.errorCode);
-                        }
-                    }
+        InFlightRequest inflightReq = {1, false, supportsPartialResults,
+                                       partialResultCount, resultQueue};
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+        Return<void> ret;
+        ret = session->constructDefaultRequestSettings(reqTemplate,
+                                                       [&](auto status, const auto& req) {
+                                                           ASSERT_EQ(Status::OK, status);
+                                                           settings = req;
+                                                       });
+        ASSERT_TRUE(ret.isOk());
 
-                    ret = session->close();
-                    ASSERT_TRUE(ret.isOk());
+        sp<GraphicBuffer> gb = new GraphicBuffer(
+            previewStream.width, previewStream.height,
+            static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat), 1,
+            android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
+                                            halStreamConfig.streams[0].consumerUsage));
+        ASSERT_NE(nullptr, gb.get());
+        StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+                                     bufferId,
+                                     hidl_handle(gb->getNativeBuffer()->handle),
+                                     BufferStatus::OK,
+                                     nullptr,
+                                     nullptr};
+        ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
+        const StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+                                               BufferStatus::ERROR, nullptr, nullptr};
+        CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
+                                  emptyInputBuffer, outputBuffers};
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            mInflightMap.clear();
+            mInflightMap.add(frameNumber, &inflightReq);
+        }
+
+        Status status = Status::INTERNAL_ERROR;
+        uint32_t numRequestProcessed = 0;
+        hidl_vec<BufferCache> cachesToRemove;
+        ret = session->processCaptureRequest(
+            {request}, cachesToRemove, [&status, &numRequestProcessed](auto s,
+                    uint32_t n) {
+                status = s;
+                numRequestProcessed = n;
+            });
+
+        ASSERT_TRUE(ret.isOk());
+        ASSERT_EQ(Status::OK, status);
+        ASSERT_EQ(numRequestProcessed, 1u);
+        // Flush before waiting for request to complete.
+        Return<Status> returnStatus = session->flush();
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, returnStatus);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            while (!inflightReq.errorCodeValid &&
+                   ((0 < inflightReq.numBuffersLeft) ||
+                           (!inflightReq.haveResultMetadata))) {
+                auto timeout = std::chrono::system_clock::now() +
+                               std::chrono::seconds(kStreamBufferTimeoutSec);
+                ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l,
+                        timeout));
+            }
+
+            if (!inflightReq.errorCodeValid) {
+                ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+                ASSERT_EQ(previewStream.id, inflightReq.resultOutputBuffers[0].streamId);
+            } else {
+                switch (inflightReq.errorCode) {
+                    case ErrorCode::ERROR_REQUEST:
+                    case ErrorCode::ERROR_RESULT:
+                    case ErrorCode::ERROR_BUFFER:
+                        // Expected
+                        break;
+                    case ErrorCode::ERROR_DEVICE:
+                    default:
+                        FAIL() << "Unexpected error:"
+                               << static_cast<uint32_t>(inflightReq.errorCode);
                 }
             }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+
+            ret = session->close();
+            ASSERT_TRUE(ret.isOk());
         }
     }
 }
@@ -3400,44 +3775,37 @@
 
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
-        switch (deviceVersion) {
-            case CAMERA_DEVICE_API_VERSION_3_3:
-            case CAMERA_DEVICE_API_VERSION_3_2: {
-                Stream previewStream;
-                HalStreamConfiguration halStreamConfig;
-                sp<ICameraDeviceSession> session;
-                bool supportsPartialResults = false;
-                uint32_t partialResultCount = 0;
-                configurePreviewStream(name, mProvider, &previewThreshold, &session /*out*/,
-                                       &previewStream /*out*/, &halStreamConfig /*out*/,
-                                       &supportsPartialResults /*out*/,
-                                       &partialResultCount /*out*/);
-
-                Return<Status> returnStatus = session->flush();
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, returnStatus);
-
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    auto timeout = std::chrono::system_clock::now() +
-                                   std::chrono::milliseconds(kEmptyFlushTimeoutMSec);
-                    ASSERT_EQ(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
-                }
-
-                Return<void> ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-            }
-            break;
-            case CAMERA_DEVICE_API_VERSION_1_0: {
-                //Not applicable
-            }
-            break;
-            default: {
-                ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
-                ADD_FAILURE();
-            }
-            break;
+        if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+            continue;
+        } else if (deviceVersion <= 0) {
+            ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+            ADD_FAILURE();
+            return;
         }
+
+        V3_2::Stream previewStream;
+        HalStreamConfiguration halStreamConfig;
+        sp<ICameraDeviceSession> session;
+        bool supportsPartialResults = false;
+        uint32_t partialResultCount = 0;
+        configurePreviewStream(name, deviceVersion, mProvider, &previewThreshold, &session /*out*/,
+                &previewStream /*out*/, &halStreamConfig /*out*/,
+                &supportsPartialResults /*out*/,
+                &partialResultCount /*out*/);
+
+        Return<Status> returnStatus = session->flush();
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, returnStatus);
+
+        {
+            std::unique_lock<std::mutex> l(mLock);
+            auto timeout = std::chrono::system_clock::now() +
+                           std::chrono::milliseconds(kEmptyFlushTimeoutMSec);
+            ASSERT_EQ(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+        }
+
+        Return<void> ret = session->close();
+        ASSERT_TRUE(ret.isOk());
     }
 }
 
@@ -3480,6 +3848,59 @@
     return Status::OK;
 }
 
+// Check if the camera device has logical multi-camera capability.
+Status CameraHidlTest::isLogicalMultiCamera(camera_metadata_t *staticMeta) {
+    Status ret = Status::METHOD_NOT_SUPPORTED;
+    if (nullptr == staticMeta) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    for (size_t i = 0; i < entry.count; i++) {
+        if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA == entry.data.u8[i]) {
+            ret = Status::OK;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+// Generate a list of physical camera ids backing a logical multi-camera.
+Status CameraHidlTest::getPhysicalCameraIds(camera_metadata_t *staticMeta,
+        std::unordered_set<std::string> *physicalIds) {
+    if ((nullptr == staticMeta) || (nullptr == physicalIds)) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    camera_metadata_ro_entry entry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
+            &entry);
+    if (0 != rc) {
+        return Status::ILLEGAL_ARGUMENT;
+    }
+
+    const uint8_t* ids = entry.data.u8;
+    size_t start = 0;
+    for (size_t i = 0; i < entry.count; i++) {
+        if (ids[i] == '\0') {
+            if (start != i) {
+                std::string currentId(reinterpret_cast<const char *> (ids + start));
+                physicalIds->emplace(currentId);
+            }
+            start = i + 1;
+        }
+    }
+
+    return Status::OK;
+}
+
 // Check if constrained mode is supported by using the static
 // camera characteristics.
 Status CameraHidlTest::isConstrainedModeAvailable(camera_metadata_t *staticMeta) {
@@ -3624,12 +4045,136 @@
     return Status::METHOD_NOT_SUPPORTED;
 }
 
+void CameraHidlTest::createStreamConfiguration(
+        const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
+        StreamConfigurationMode configMode,
+        ::android::hardware::camera::device::V3_2::StreamConfiguration *config3_2 /*out*/,
+        ::android::hardware::camera::device::V3_4::StreamConfiguration *config3_4 /*out*/) {
+    ASSERT_NE(nullptr, config3_2);
+    ASSERT_NE(nullptr, config3_4);
+
+    ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(streams3_2.size());
+    size_t idx = 0;
+    for (auto& stream3_2 : streams3_2) {
+        V3_4::Stream stream;
+        stream.v3_2 = stream3_2;
+        streams3_4[idx++] = stream;
+    }
+    *config3_4 = {streams3_4, configMode, {}};
+    *config3_2 = {streams3_2, configMode};
+}
+
+// Configure multiple preview streams using different physical ids.
+void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
+        sp<ICameraProvider> provider,
+        const AvailableStream *previewThreshold,
+        const std::unordered_set<std::string>& physicalIds,
+        sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
+        V3_2::Stream *previewStream /*out*/,
+        device::V3_4::HalStreamConfiguration *halStreamConfig /*out*/,
+        bool *supportsPartialResults /*out*/,
+        uint32_t *partialResultCount /*out*/) {
+    ASSERT_NE(nullptr, session3_4);
+    ASSERT_NE(nullptr, halStreamConfig);
+    ASSERT_NE(nullptr, previewStream);
+    ASSERT_NE(nullptr, supportsPartialResults);
+    ASSERT_NE(nullptr, partialResultCount);
+    ASSERT_FALSE(physicalIds.empty());
+
+    std::vector<AvailableStream> outputPreviewStreams;
+    ::android::sp<ICameraDevice> device3_x;
+    ALOGI("configureStreams: Testing camera device %s", name.c_str());
+    Return<void> ret;
+    ret = provider->getCameraDeviceInterface_V3_x(
+        name,
+        [&](auto status, const auto& device) {
+            ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                  (int)status);
+            ASSERT_EQ(Status::OK, status);
+            ASSERT_NE(device, nullptr);
+            device3_x = device;
+        });
+    ASSERT_TRUE(ret.isOk());
+
+    sp<DeviceCb> cb = new DeviceCb(this);
+    sp<ICameraDeviceSession> session;
+    ret = device3_x->open(
+        cb,
+        [&session](auto status, const auto& newSession) {
+            ALOGI("device::open returns status:%d", (int)status);
+            ASSERT_EQ(Status::OK, status);
+            ASSERT_NE(newSession, nullptr);
+            session = newSession;
+        });
+    ASSERT_TRUE(ret.isOk());
+
+    sp<device::V3_3::ICameraDeviceSession> session3_3;
+    castSession(session, deviceVersion, &session3_3, session3_4);
+    ASSERT_NE(nullptr, session3_4);
+
+    camera_metadata_t *staticMeta;
+    ret = device3_x->getCameraCharacteristics([&] (Status s,
+            CameraMetadata metadata) {
+        ASSERT_EQ(Status::OK, s);
+        staticMeta = clone_camera_metadata(
+                reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+         ASSERT_NE(nullptr, staticMeta);
+    });
+    ASSERT_TRUE(ret.isOk());
+
+    camera_metadata_ro_entry entry;
+    auto status = find_camera_metadata_ro_entry(staticMeta,
+            ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+    if ((0 == status) && (entry.count > 0)) {
+        *partialResultCount = entry.data.i32[0];
+        *supportsPartialResults = (*partialResultCount > 1);
+    }
+
+    outputPreviewStreams.clear();
+    auto rc = getAvailableOutputStreams(staticMeta,
+            outputPreviewStreams, previewThreshold);
+    free_camera_metadata(staticMeta);
+    ASSERT_EQ(Status::OK, rc);
+    ASSERT_FALSE(outputPreviewStreams.empty());
+
+    ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(physicalIds.size());
+    int32_t streamId = 0;
+    for (auto const& physicalId : physicalIds) {
+        V3_4::Stream stream3_4 = {{streamId, StreamType::OUTPUT,
+            static_cast<uint32_t> (outputPreviewStreams[0].width),
+            static_cast<uint32_t> (outputPreviewStreams[0].height),
+            static_cast<PixelFormat> (outputPreviewStreams[0].format),
+            GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, StreamRotation::ROTATION_0},
+            physicalId.c_str(), /*bufferSize*/ 0};
+        streams3_4[streamId++] = stream3_4;
+    }
+
+    ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+    config3_4 = {streams3_4, StreamConfigurationMode::NORMAL_MODE, {}};
+    RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+    ret = (*session3_4)->constructDefaultRequestSettings(reqTemplate,
+            [&config3_4](auto status, const auto& req) {
+            ASSERT_EQ(Status::OK, status);
+            config3_4.sessionParams = req;
+            });
+    ASSERT_TRUE(ret.isOk());
+
+    ret = (*session3_4)->configureStreams_3_4(config3_4,
+            [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) {
+            ASSERT_EQ(Status::OK, s);
+            ASSERT_EQ(physicalIds.size(), halConfig.streams.size());
+            *halStreamConfig = halConfig;
+            });
+    *previewStream = streams3_4[0].v3_2;
+    ASSERT_TRUE(ret.isOk());
+}
+
 // Open a device session and configure a preview stream.
-void CameraHidlTest::configurePreviewStream(const std::string &name,
+void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t deviceVersion,
         sp<ICameraProvider> provider,
         const AvailableStream *previewThreshold,
         sp<ICameraDeviceSession> *session /*out*/,
-        Stream *previewStream /*out*/,
+        V3_2::Stream *previewStream /*out*/,
         HalStreamConfiguration *halStreamConfig /*out*/,
         bool *supportsPartialResults /*out*/,
         uint32_t *partialResultCount /*out*/) {
@@ -3665,9 +4210,9 @@
         });
     ASSERT_TRUE(ret.isOk());
 
-    auto castResult = device::V3_3::ICameraDeviceSession::castFrom(*session);
-    ASSERT_TRUE(castResult.isOk());
-    sp<device::V3_3::ICameraDeviceSession> session3_3 = castResult;
+    sp<device::V3_3::ICameraDeviceSession> session3_3;
+    sp<device::V3_4::ICameraDeviceSession> session3_4;
+    castSession(*session, deviceVersion, &session3_3, &session3_4);
 
     camera_metadata_t *staticMeta;
     ret = device3_x->getCameraCharacteristics([&] (Status s,
@@ -3694,23 +4239,35 @@
     ASSERT_EQ(Status::OK, rc);
     ASSERT_FALSE(outputPreviewStreams.empty());
 
-    *previewStream = {0, StreamType::OUTPUT,
+    V3_2::Stream stream3_2 = {0, StreamType::OUTPUT,
             static_cast<uint32_t> (outputPreviewStreams[0].width),
             static_cast<uint32_t> (outputPreviewStreams[0].height),
             static_cast<PixelFormat> (outputPreviewStreams[0].format),
             GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, 0, StreamRotation::ROTATION_0};
-    ::android::hardware::hidl_vec<Stream> streams = {*previewStream};
-    StreamConfiguration config = {streams,
-            StreamConfigurationMode::NORMAL_MODE};
-    if (session3_3 == nullptr) {
-        ret = (*session)->configureStreams(config,
-                [&] (Status s, HalStreamConfiguration halConfig) {
+    ::android::hardware::hidl_vec<V3_2::Stream> streams3_2 = {stream3_2};
+    ::android::hardware::camera::device::V3_2::StreamConfiguration config3_2;
+    ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+    createStreamConfiguration(streams3_2, StreamConfigurationMode::NORMAL_MODE,
+                              &config3_2, &config3_4);
+    if (session3_4 != nullptr) {
+        RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+        ret = session3_4->constructDefaultRequestSettings(reqTemplate,
+                                                       [&config3_4](auto status, const auto& req) {
+                                                           ASSERT_EQ(Status::OK, status);
+                                                           config3_4.sessionParams = req;
+                                                       });
+        ASSERT_TRUE(ret.isOk());
+        ret = session3_4->configureStreams_3_4(config3_4,
+                [&] (Status s, device::V3_4::HalStreamConfiguration halConfig) {
                     ASSERT_EQ(Status::OK, s);
                     ASSERT_EQ(1u, halConfig.streams.size());
-                    *halStreamConfig = halConfig;
+                    halStreamConfig->streams.resize(halConfig.streams.size());
+                    for (size_t i = 0; i < halConfig.streams.size(); i++) {
+                        halStreamConfig->streams[i] = halConfig.streams[i].v3_3.v3_2;
+                    }
                 });
-    } else {
-        ret = session3_3->configureStreams_3_3(config,
+    } else if (session3_3 != nullptr) {
+        ret = session3_3->configureStreams_3_3(config3_2,
                 [&] (Status s, device::V3_3::HalStreamConfiguration halConfig) {
                     ASSERT_EQ(Status::OK, s);
                     ASSERT_EQ(1u, halConfig.streams.size());
@@ -3719,15 +4276,48 @@
                         halStreamConfig->streams[i] = halConfig.streams[i].v3_2;
                     }
                 });
+    } else {
+        ret = (*session)->configureStreams(config3_2,
+                [&] (Status s, HalStreamConfiguration halConfig) {
+                    ASSERT_EQ(Status::OK, s);
+                    ASSERT_EQ(1u, halConfig.streams.size());
+                    *halStreamConfig = halConfig;
+                });
     }
+    *previewStream = stream3_2;
     ASSERT_TRUE(ret.isOk());
 }
 
+//Cast camera device session to corresponding version
+void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
+        sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
+        sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/) {
+    ASSERT_NE(nullptr, session3_3);
+    ASSERT_NE(nullptr, session3_4);
+
+    switch (deviceVersion) {
+        case CAMERA_DEVICE_API_VERSION_3_4: {
+            auto castResult = device::V3_4::ICameraDeviceSession::castFrom(session);
+            ASSERT_TRUE(castResult.isOk());
+            *session3_4 = castResult;
+            break;
+        }
+        case CAMERA_DEVICE_API_VERSION_3_3: {
+            auto castResult = device::V3_3::ICameraDeviceSession::castFrom(session);
+            ASSERT_TRUE(castResult.isOk());
+            *session3_3 = castResult;
+            break;
+        }
+        default:
+            //no-op
+            return;
+    }
+}
+
 // Open a device session with empty callbacks and return static metadata.
 void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
         sp<ICameraProvider> provider,
         sp<ICameraDeviceSession> *session /*out*/,
-        sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
         camera_metadata_t **staticMeta /*out*/) {
     ASSERT_NE(nullptr, session);
     ASSERT_NE(nullptr, staticMeta);
@@ -3763,12 +4353,6 @@
         ASSERT_NE(nullptr, *staticMeta);
     });
     ASSERT_TRUE(ret.isOk());
-
-    if(session3_3 != nullptr) {
-        auto castResult = device::V3_3::ICameraDeviceSession::castFrom(*session);
-        ASSERT_TRUE(castResult.isOk());
-        *session3_3 = castResult;
-    }
 }
 
 // Open a particular camera device.
diff --git a/cas/1.0/CasHal.mk b/cas/1.0/CasHal.mk
deleted file mode 100644
index 3cae6bf..0000000
--- a/cas/1.0/CasHal.mk
+++ /dev/null
@@ -1,192 +0,0 @@
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-########################################################################
-# Included by frameworks/base for MediaCas. Hidl HAL can't be linked as
-# Java lib from frameworks because it has dependency on frameworks itself.
-#
-
-intermediates := $(TARGET_OUT_COMMON_GEN)/JAVA_LIBRARIES/android.hardware.cas-V1.0-java_intermediates
-
-HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
-HIDL_PATH := system/libhidl/transport/base/1.0
-
-#
-# Build types.hal (DebugInfo)
-#
-GEN := $(intermediates)/android/hidl/base/V1_0/DebugInfo.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hidl:system/libhidl/transport \
-        android.hidl.base@1.0::types.DebugInfo
-
-$(GEN): $(HIDL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build IBase.hal
-#
-GEN := $(intermediates)/android/hidl/base/V1_0/IBase.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IBase.hal
-$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal
-$(GEN): $(HIDL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hidl:system/libhidl/transport \
-        android.hidl.base@1.0::IBase
-
-$(GEN): $(HIDL_PATH)/IBase.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-HIDL_PATH := hardware/interfaces/cas/1.0
-
-#
-# Build types.hal (HidlCasPluginDescriptor)
-#
-GEN := $(intermediates)/android/hardware/cas/V1_0/HidlCasPluginDescriptor.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.cas@1.0::types.HidlCasPluginDescriptor
-
-$(GEN): $(HIDL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (Status)
-#
-GEN := $(intermediates)/android/hardware/cas/V1_0/Status.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.cas@1.0::types.Status
-
-$(GEN): $(HIDL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build ICas.hal
-#
-GEN := $(intermediates)/android/hardware/cas/V1_0/ICas.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/ICas.hal
-$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal
-$(GEN): $(HIDL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.cas@1.0::ICas
-
-$(GEN): $(HIDL_PATH)/ICas.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build ICasListener.hal
-#
-GEN := $(intermediates)/android/hardware/cas/V1_0/ICasListener.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/ICasListener.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.cas@1.0::ICasListener
-
-$(GEN): $(HIDL_PATH)/ICasListener.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build IDescramblerBase.hal
-#
-GEN := $(intermediates)/android/hardware/cas/V1_0/IDescramblerBase.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IDescramblerBase.hal
-$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal
-$(GEN): $(HIDL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.cas@1.0::IDescramblerBase
-
-$(GEN): $(HIDL_PATH)/IDescramblerBase.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build IMediaCasService.hal
-#
-GEN := $(intermediates)/android/hardware/cas/V1_0/IMediaCasService.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IMediaCasService.hal
-$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/ICas.hal
-$(GEN): $(HIDL_PATH)/ICas.hal
-$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/ICasListener.hal
-$(GEN): $(HIDL_PATH)/ICasListener.hal
-$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/IDescramblerBase.hal
-$(GEN): $(HIDL_PATH)/IDescramblerBase.hal
-$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal
-$(GEN): $(HIDL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.cas@1.0::IMediaCasService
-
-$(GEN): $(HIDL_PATH)/IMediaCasService.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
diff --git a/cas/1.0/default/CasImpl.cpp b/cas/1.0/default/CasImpl.cpp
index 9d1f4a3..2ac1c4f 100644
--- a/cas/1.0/default/CasImpl.cpp
+++ b/cas/1.0/default/CasImpl.cpp
@@ -103,6 +103,7 @@
     status_t err = INVALID_OPERATION;
     if (holder != NULL) {
         err = holder->get()->openSession(&sessionId);
+        holder.clear();
     }
 
     _hidl_cb(toStatus(err), sessionId);
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service.rc b/cas/1.0/default/android.hardware.cas@1.0-service.rc
index 93de794..74f2f96 100644
--- a/cas/1.0/default/android.hardware.cas@1.0-service.rc
+++ b/cas/1.0/default/android.hardware.cas@1.0-service.rc
@@ -1,4 +1,4 @@
-service cas-hal-1-0 /vendor/bin/hw/android.hardware.cas@1.0-service
+service vendor.cas-hal-1-0 /vendor/bin/hw/android.hardware.cas@1.0-service
     class hal
     user media
     group mediadrm drmrpc
diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
index d3b0f1d..193253a 100644
--- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
+++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
@@ -223,12 +223,26 @@
     sp<ICas> mMediaCas;
     sp<IDescramblerBase> mDescramblerBase;
     sp<MediaCasListener> mCasListener;
+    typedef struct _OobInputTestParams {
+        const SubSample* subSamples;
+        uint32_t numSubSamples;
+        size_t imemSizeActual;
+        uint64_t imemOffset;
+        uint64_t imemSize;
+        uint64_t srcOffset;
+        uint64_t dstOffset;
+    } OobInputTestParams;
 
     ::testing::AssertionResult createCasPlugin(int32_t caSystemId);
     ::testing::AssertionResult openCasSession(std::vector<uint8_t>* sessionId);
-    ::testing::AssertionResult descrambleTestInputBuffer(const sp<IDescrambler>& descrambler,
-                                                         Status* descrambleStatus,
-                                                         sp<IMemory>* hidlInMemory);
+    ::testing::AssertionResult descrambleTestInputBuffer(
+            const sp<IDescrambler>& descrambler,
+            Status* descrambleStatus,
+            sp<IMemory>* hidlInMemory);
+    ::testing::AssertionResult descrambleTestOobInput(
+            const sp<IDescrambler>& descrambler,
+            Status* descrambleStatus,
+            const OobInputTestParams& params);
 };
 
 ::testing::AssertionResult MediaCasHidlTest::createCasPlugin(int32_t caSystemId) {
@@ -332,6 +346,72 @@
     return ::testing::AssertionResult(returnVoid.isOk());
 }
 
+::testing::AssertionResult MediaCasHidlTest::descrambleTestOobInput(
+        const sp<IDescrambler>& descrambler,
+        Status* descrambleStatus,
+        const OobInputTestParams& params) {
+    hidl_vec<SubSample> hidlSubSamples;
+    hidlSubSamples.setToExternal(
+            const_cast<SubSample*>(params.subSamples), params.numSubSamples, false /*own*/);
+
+    sp<MemoryDealer> dealer = new MemoryDealer(params.imemSizeActual, "vts-cas");
+    if (nullptr == dealer.get()) {
+        ALOGE("couldn't get MemoryDealer!");
+        return ::testing::AssertionFailure();
+    }
+
+    sp<IMemory> mem = dealer->allocate(params.imemSizeActual);
+    if (nullptr == mem.get()) {
+        ALOGE("couldn't allocate IMemory!");
+        return ::testing::AssertionFailure();
+    }
+
+    // build hidl_memory from memory heap
+    ssize_t offset;
+    size_t size;
+    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
+    if (nullptr == heap.get()) {
+        ALOGE("couldn't get memory heap!");
+        return ::testing::AssertionFailure();
+    }
+
+    native_handle_t* nativeHandle = native_handle_create(1, 0);
+    if (!nativeHandle) {
+        ALOGE("failed to create native handle!");
+        return ::testing::AssertionFailure();
+    }
+    nativeHandle->data[0] = heap->getHeapID();
+
+    SharedBuffer srcBuffer = {
+            .heapBase = hidl_memory("ashmem", hidl_handle(nativeHandle), heap->getSize()),
+            .offset = (uint64_t) offset + params.imemOffset,
+            .size = (uint64_t) params.imemSize,
+    };
+
+    DestinationBuffer dstBuffer;
+    dstBuffer.type = BufferType::SHARED_MEMORY;
+    dstBuffer.nonsecureMemory = srcBuffer;
+
+    uint32_t outBytes;
+    hidl_string detailedError;
+    auto returnVoid = descrambler->descramble(
+        ScramblingControl::EVENKEY /*2*/, hidlSubSamples,
+        srcBuffer,
+        params.srcOffset,
+        dstBuffer,
+        params.dstOffset,
+        [&](Status status, uint32_t bytesWritten, const hidl_string& detailedErr) {
+            *descrambleStatus = status;
+            outBytes = bytesWritten;
+            detailedError = detailedErr;
+        });
+    if (!returnVoid.isOk() || *descrambleStatus != Status::OK) {
+        ALOGI("descramble failed, trans=%s, status=%d, outBytes=%u, error=%s",
+              returnVoid.description().c_str(), *descrambleStatus, outBytes, detailedError.c_str());
+    }
+    return ::testing::AssertionResult(returnVoid.isOk());
+}
+
 TEST_F(MediaCasHidlTest, EnumeratePlugins) {
     description("Test enumerate plugins");
     hidl_vec<HidlCasPluginDescriptor> descriptors;
@@ -613,6 +693,153 @@
     EXPECT_FALSE(mDescramblerBase->requiresSecureDecoderComponent("bad"));
 }
 
+TEST_F(MediaCasHidlTest, TestClearKeyOobFails) {
+    description("Test that oob descramble request fails with expected error");
+
+    ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+    auto returnStatus = mMediaCas->provision(hidl_string(PROVISION_STR));
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    std::vector<uint8_t> sessionId;
+    ASSERT_TRUE(openCasSession(&sessionId));
+
+    returnStatus = mDescramblerBase->setMediaCasSession(sessionId);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    hidl_vec<uint8_t> hidlEcm;
+    hidlEcm.setToExternal(const_cast<uint8_t*>(kEcmBinaryBuffer), sizeof(kEcmBinaryBuffer));
+    returnStatus = mMediaCas->processEcm(sessionId, hidlEcm);
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    sp<IDescrambler> descrambler = IDescrambler::castFrom(mDescramblerBase);
+    ASSERT_NE(nullptr, descrambler.get());
+
+    Status descrambleStatus = Status::OK;
+
+    // test invalid src buffer offset
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = kSubSamples,
+                .numSubSamples  = sizeof(kSubSamples)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0xcccccc,
+                .imemSize       = sizeof(kInBinaryBuffer),
+                .srcOffset      = 0,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test invalid src buffer size
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = kSubSamples,
+                .numSubSamples  = sizeof(kSubSamples)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0,
+                .imemSize       = 0xcccccc,
+                .srcOffset      = 0,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test invalid src buffer size
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = kSubSamples,
+                .numSubSamples  = sizeof(kSubSamples)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 1,
+                .imemSize       = (uint64_t)-1,
+                .srcOffset      = 0,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test invalid srcOffset
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = kSubSamples,
+                .numSubSamples  = sizeof(kSubSamples)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0,
+                .imemSize       = sizeof(kInBinaryBuffer),
+                .srcOffset      = 0xcccccc,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test invalid dstOffset
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = kSubSamples,
+                .numSubSamples  = sizeof(kSubSamples)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0,
+                .imemSize       = sizeof(kInBinaryBuffer),
+                .srcOffset      = 0,
+                .dstOffset      = 0xcccccc
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test detection of oob subsample sizes
+    const SubSample invalidSubSamples1[] =
+        {{162, 0}, {0, 184}, {0, 0xdddddd}};
+
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = invalidSubSamples1,
+                .numSubSamples  = sizeof(invalidSubSamples1)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0,
+                .imemSize       = sizeof(kInBinaryBuffer),
+                .srcOffset      = 0,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    // test detection of overflowing subsample sizes
+    const SubSample invalidSubSamples2[] =
+        {{162, 0}, {0, 184}, {2, (uint32_t)-1}};
+
+    ASSERT_TRUE(descrambleTestOobInput(
+            descrambler,
+            &descrambleStatus,
+            {
+                .subSamples     = invalidSubSamples2,
+                .numSubSamples  = sizeof(invalidSubSamples2)/sizeof(SubSample),
+                .imemSizeActual = sizeof(kInBinaryBuffer),
+                .imemOffset     = 0,
+                .imemSize       = sizeof(kInBinaryBuffer),
+                .srcOffset      = 0,
+                .dstOffset      = 0
+            }));
+    EXPECT_EQ(Status::BAD_VALUE, descrambleStatus);
+
+    returnStatus = mDescramblerBase->release();
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+
+    returnStatus = mMediaCas->release();
+    EXPECT_TRUE(returnStatus.isOk());
+    EXPECT_EQ(Status::OK, returnStatus);
+}
+
 }  // anonymous namespace
 
 int main(int argc, char** argv) {
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 5aecea0..002ff31 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -16,6 +16,14 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.authsecret</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAuthSecret</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.automotive.evs</name>
         <version>1.0</version>
         <interface>
@@ -155,9 +163,9 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="hidl" optional="true">
+    <hal format="hidl" optional="false">
         <name>android.hardware.health</name>
-        <version>1.0</version>
+        <version>2.0</version>
         <interface>
             <name>IHealth</name>
             <instance>default</instance>
@@ -221,7 +229,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.power</name>
-        <version>1.0-1</version>
+        <version>1.0-2</version>
         <interface>
             <name>IPower</name>
             <instance>default</instance>
diff --git a/configstore/1.0/default/Android.mk b/configstore/1.0/default/Android.mk
index eb857f8..22d7c92 100644
--- a/configstore/1.0/default/Android.mk
+++ b/configstore/1.0/default/Android.mk
@@ -22,7 +22,7 @@
     libhwminijail \
     liblog \
     libutils \
-    android.hardware.configstore@1.0 \
+    android.hardware.configstore@1.0
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/configstore/1.0/default/android.hardware.configstore@1.0-service.rc b/configstore/1.0/default/android.hardware.configstore@1.0-service.rc
index 563d854..40fb498 100644
--- a/configstore/1.0/default/android.hardware.configstore@1.0-service.rc
+++ b/configstore/1.0/default/android.hardware.configstore@1.0-service.rc
@@ -1,4 +1,4 @@
-service configstore-hal-1-0 /vendor/bin/hw/android.hardware.configstore@1.0-service
+service vendor.configstore-hal-1-0 /vendor/bin/hw/android.hardware.configstore@1.0-service
     class hal animation
     user system
     group system
diff --git a/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy b/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy
index 43bf1fa..f2dd892 100644
--- a/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy
+++ b/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy
@@ -17,7 +17,9 @@
 ioctl: arg1 == 0xc0306201
 # prctl: arg0 == PR_SET_NAME || arg0 == PR_SET_VMA || arg0 == PR_SET_TIMERSLACK
 # || arg0 == PR_GET_NO_NEW_PRIVS # used by crash_dump
-prctl: arg0 == 15 || arg0 == 0x53564d41 || arg0 == 29 || arg0 == 39
+# prctl: arg0 == 15 || arg0 == 0x53564d41 || arg0 == 29 || arg0 == 39
+# TODO(b/68162846) reduce scope of prctl() based on arguments
+prctl: 1
 openat: 1
 mmap: 1
 mprotect: 1
@@ -28,6 +30,7 @@
 write: 1
 fstat: 1
 clone: 1
+sched_setscheduler: 1
 munmap: 1
 lseek: 1
 sigaltstack: 1
diff --git a/confirmationui/1.0/Android.bp b/confirmationui/1.0/Android.bp
new file mode 100644
index 0000000..21acecb
--- /dev/null
+++ b/confirmationui/1.0/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.confirmationui@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IConfirmationResultCallback.hal",
+        "IConfirmationUI.hal",
+    ],
+    interfaces: [
+        "android.hardware.keymaster@4.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "MessageSize",
+        "ResponseCode",
+        "TestKeyBits",
+        "TestModeCommands",
+        "UIOption",
+    ],
+    gen_java: false,
+}
+
diff --git a/confirmationui/1.0/IConfirmationResultCallback.hal b/confirmationui/1.0/IConfirmationResultCallback.hal
new file mode 100644
index 0000000..03a10cf
--- /dev/null
+++ b/confirmationui/1.0/IConfirmationResultCallback.hal
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.confirmationui@1.0;
+
+/**
+ * Callback interface passed to IConfirmationUI::promptUserConfirmation().
+ * Informs the caller about the result of the prompt operation.
+ */
+interface IConfirmationResultCallback {
+    /**
+     * This callback is called by the confirmation provider when it stops prompting the user.
+     * Iff the user has confirmed the prompted text, error is ErrorCode::OK and the
+     * parameters formattedMessage and confirmationToken hold the values needed to request
+     * a signature from keymaster.
+     * In all other cases formattedMessage and confirmationToken must be of length 0.
+     *
+     * @param error - OK: IFF the user has confirmed the prompt.
+     *              - Canceled: If the user has pressed the cancel button.
+     *              - Aborted: If IConfirmationUI::abort() was called.
+     *              - SystemError: If an unexpected System error occurred that prevented the TUI
+     *                             from being shut down gracefully.
+     * @param formattedMessage holds the prompt text and extra data.
+     *                         The message is CBOR (RFC 7049) encoded and has the following format:
+     *                         CBOR_MAP{ "prompt", <promptText>, "extra", <extraData> }
+     *                         The message is a CBOR encoded map (type 5) with the keys
+     *                         "prompt" and "extra". The keys are encoded as CBOR text string
+     *                         (type 3). The value <promptText> is encoded as CBOR text string
+     *                         (type 3), and the value <extraData> is encoded as CBOR byte string
+     *                         (type 2). The map must have exactly one key value pair for each of
+     *                         the keys "prompt" and "extra". Other keys are not allowed.
+     *                         The value of "prompt" is given by the proptText argument to
+     *                         IConfirmationUI::promptUserConfirmation and must not be modified
+     *                         by the implementation.
+     *                         The value of "extra" is given by the extraData argument to
+     *                         IConfirmationUI::promptUserConfirmation and must not be modified
+     *                         or interpreted by the implementation.
+     *
+     * @param confirmationToken a 32-byte HMAC-SHA256 value, computed over
+     *                          "confirmation token" || <formattedMessage>
+     *                          i.e. the literal UTF-8 encoded string "confirmation token", without
+     *                          the "", concatenated with the formatted message as returned in the
+     *                          formattedMessage argument. The HMAC is keyed with a 256-bit secret
+     *                          which is shared with Keymaster. In test mode the test key MUST be
+     *                          used (see types.hal TestModeCommands and TestKeyBits).
+     */
+    result(ResponseCode error, vec<uint8_t> formattedMessage, vec<uint8_t> confirmationToken);
+};
diff --git a/confirmationui/1.0/IConfirmationUI.hal b/confirmationui/1.0/IConfirmationUI.hal
new file mode 100644
index 0000000..db8055d
--- /dev/null
+++ b/confirmationui/1.0/IConfirmationUI.hal
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.confirmationui@1.0;
+
+import android.hardware.keymaster@4.0::HardwareAuthToken;
+import IConfirmationResultCallback;
+
+interface IConfirmationUI {
+    /**
+     * Asynchronously initiates a confirmation UI dialog prompting the user to confirm a given text.
+     * The TUI prompt must be implemented in such a way that a positive response indicates with
+     * high confidence that a user has seen the given prompt text even if the Android framework
+     * including the kernel was compromised.
+     *
+     * @param resultCB Implementation of IResultCallback. Used by the implementation to report
+     *                 the result of the current pending user prompt.
+     *
+     * @param promptText UTF-8 encoded string which is to be presented to the user.
+     *
+     * @param extraData A binary blob that must be included in the formatted output message as is.
+     *                  It is opaque to the implementation. Implementations must neither interpret
+     *                  nor modify the content.
+     *
+     * @param locale String specifying the locale that must be used by the TUI dialog. The string
+     *                      is an IETF BCP 47 tag.
+     *
+     * @param uiOptions A set of uiOptions manipulating how the confirmation prompt is displayed.
+     *                  Refer to UIOption in types.hal for possible options.
+     *
+     * @return error  - OK: IFF the dialog was successfully started. In this case, and only in this
+     *                      case, the implementation must, eventually, call the callback to
+     *                      indicate completion.
+     *                - OperationPending: Is returned when the confirmation provider is currently
+     *                      in use.
+     *                - SystemError: An error occurred trying to communicate with the confirmation
+     *                      provider (e.g. trusted app).
+     *                - UIError: The confirmation provider encountered an issue with displaying
+     *                      the prompt text to the user.
+     */
+    promptUserConfirmation(IConfirmationResultCallback resultCB, string promptText,
+                           vec<uint8_t> extraData, string locale, vec<UIOption> uiOptions)
+        generates(ResponseCode error);
+
+    /**
+     * DeliverSecureInput is used by the framework to deliver a secure input event to the
+     * confirmation provider.
+     *
+     * VTS test mode:
+     * This function can be used to test certain code paths non-interactively. See TestModeCommands
+     * in types.hal for details.
+     *
+     * @param secureInputToken An authentication token as generated by Android authentication
+     *                         providers.
+     *
+     * @return error - Ignored: Unless used for testing (See TestModeCommands).
+     */
+    deliverSecureInputEvent(HardwareAuthToken secureInputToken)
+        generates(ResponseCode error);
+
+    /**
+     * Aborts a pending user prompt. This allows the framework to gracefully end a TUI dialog.
+     * If a TUI operation was pending the corresponding call back is informed with
+     * ErrorCode::Aborted.
+     */
+    abort();
+};
+
diff --git a/confirmationui/1.0/default/Android.bp b/confirmationui/1.0/default/Android.bp
new file mode 100644
index 0000000..10018e8
--- /dev/null
+++ b/confirmationui/1.0/default/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+    name: "android.hardware.confirmationui@1.0-service",
+    init_rc: ["android.hardware.confirmationui@1.0-service.rc"],
+    vendor: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "service.cpp",
+        "ConfirmationUI.cpp",
+        "PlatformSpecifics.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.confirmationui@1.0",
+        "android.hardware.confirmationui-support-lib",
+        "android.hardware.keymaster@4.0",
+        "libcrypto",
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+    ],
+}
\ No newline at end of file
diff --git a/confirmationui/1.0/default/ConfirmationUI.cpp b/confirmationui/1.0/default/ConfirmationUI.cpp
new file mode 100644
index 0000000..f241a76
--- /dev/null
+++ b/confirmationui/1.0/default/ConfirmationUI.cpp
@@ -0,0 +1,66 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "ConfirmationUI.h"
+
+#include "PlatformSpecifics.h"
+
+#include <android/hardware/confirmationui/support/cbor.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+#include <android/hardware/confirmationui/1.0/generic/GenericOperation.h>
+
+#include <time.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::confirmationui::V1_0::generic::Operation;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+
+uint8_t hmacKey[32];
+
+// Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI follow.
+Return<ResponseCode> ConfirmationUI::promptUserConfirmation(
+    const sp<IConfirmationResultCallback>& resultCB, const hidl_string& promptText,
+    const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
+    const hidl_vec<UIOption>& uiOptions) {
+    auto& operation = MyOperation::get();
+    return operation.init(resultCB, promptText, extraData, locale, uiOptions);
+}
+
+Return<ResponseCode> ConfirmationUI::deliverSecureInputEvent(
+    const HardwareAuthToken& secureInputToken) {
+    auto& operation = MyOperation::get();
+    return operation.deliverSecureInputEvent(secureInputToken);
+}
+
+Return<void> ConfirmationUI::abort() {
+    auto& operation = MyOperation::get();
+    operation.abort();
+    operation.finalize(hmacKey);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/1.0/default/ConfirmationUI.h b/confirmationui/1.0/default/ConfirmationUI.h
new file mode 100644
index 0000000..e9e7f99
--- /dev/null
+++ b/confirmationui/1.0/default/ConfirmationUI.h
@@ -0,0 +1,57 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_CONFIRMATIONUI_H
+#define ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_CONFIRMATIONUI_H
+
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ConfirmationUI : public IConfirmationUI {
+    // Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI follow.
+    Return<ResponseCode> promptUserConfirmation(const sp<IConfirmationResultCallback>& resultCB,
+                                                const hidl_string& promptText,
+                                                const hidl_vec<uint8_t>& extraData,
+                                                const hidl_string& locale,
+                                                const hidl_vec<UIOption>& uiOptions) override;
+    Return<ResponseCode> deliverSecureInputEvent(
+        const ::android::hardware::keymaster::V4_0::HardwareAuthToken& secureInputToken) override;
+    Return<void> abort() override;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_CONFIRMATIONUI_H
diff --git a/confirmationui/1.0/default/OWNERS b/confirmationui/1.0/default/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/confirmationui/1.0/default/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/confirmationui/1.0/default/PlatformSpecifics.cpp b/confirmationui/1.0/default/PlatformSpecifics.cpp
new file mode 100644
index 0000000..dd039e2
--- /dev/null
+++ b/confirmationui/1.0/default/PlatformSpecifics.cpp
@@ -0,0 +1,62 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "PlatformSpecifics.h"
+
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+#include <time.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+MonotonicClockTimeStamper::TimeStamp MonotonicClockTimeStamper::now() {
+    timespec ts;
+    if (!clock_gettime(CLOCK_BOOTTIME, &ts)) {
+        return TimeStamp(ts.tv_sec * UINT64_C(1000) + ts.tv_nsec / UINT64_C(1000000));
+    } else {
+        return {};
+    }
+}
+
+support::NullOr<support::array<uint8_t, 32>> HMacImplementation::hmac256(
+    const uint8_t key[32], std::initializer_list<support::ByteBufferProxy> buffers) {
+    HMAC_CTX hmacCtx;
+    HMAC_CTX_init(&hmacCtx);
+    if (!HMAC_Init_ex(&hmacCtx, key, 32, EVP_sha256(), nullptr)) {
+        return {};
+    }
+    for (auto& buffer : buffers) {
+        if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
+            return {};
+        }
+    }
+    support::array<uint8_t, 32> result;
+    if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
+        return {};
+    }
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/1.0/default/PlatformSpecifics.h b/confirmationui/1.0/default/PlatformSpecifics.h
new file mode 100644
index 0000000..18b88c8
--- /dev/null
+++ b/confirmationui/1.0/default/PlatformSpecifics.h
@@ -0,0 +1,64 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_DEFAULT_PLATFORMSPECIFICS_H_
+#define CONFIRMATIONUI_1_0_DEFAULT_PLATFORMSPECIFICS_H_
+
+#include <stdint.h>
+#include <time.h>
+
+#include <android/hardware/confirmationui/1.0/IConfirmationResultCallback.h>
+#include <android/hardware/confirmationui/1.0/generic/GenericOperation.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+struct MonotonicClockTimeStamper {
+    class TimeStamp {
+       public:
+        explicit TimeStamp(uint64_t ts) : timestamp_(ts), ok_(true) {}
+        TimeStamp() : timestamp_(0), ok_(false) {}
+        bool isOk() const { return ok_; }
+        operator const uint64_t() const { return timestamp_; }
+
+       private:
+        uint64_t timestamp_;
+        bool ok_;
+    };
+    static TimeStamp now();
+};
+
+class HMacImplementation {
+   public:
+    static support::NullOr<support::array<uint8_t, 32>> hmac256(
+        const uint8_t key[32], std::initializer_list<support::ByteBufferProxy> buffers);
+};
+
+using MyOperation = generic::Operation<sp<IConfirmationResultCallback>, MonotonicClockTimeStamper,
+                                       HMacImplementation>;
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_DEFAULT_PLATFORMSPECIFICS_H_
diff --git a/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
new file mode 100644
index 0000000..a278028
--- /dev/null
+++ b/confirmationui/1.0/default/android.hardware.confirmationui@1.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service
+    class hal
+    user system
+    group system drmrpc
diff --git a/confirmationui/1.0/default/service.cpp b/confirmationui/1.0/default/service.cpp
new file mode 100644
index 0000000..58ec66a
--- /dev/null
+++ b/confirmationui/1.0/default/service.cpp
@@ -0,0 +1,38 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "android.hardware.confirmationui@1.0-service"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "ConfirmationUI.h"
+
+using android::hardware::joinRpcThreadpool;
+
+using android::hardware::confirmationui::V1_0::implementation::ConfirmationUI;
+
+int main() {
+    auto confirmationui = new ConfirmationUI();
+    auto status = confirmationui->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Could not register service for ConfirmationIU 1.0 (" << status << ")";
+    }
+
+    joinRpcThreadpool();
+    return -1;  // Should never get here.
+}
diff --git a/confirmationui/1.0/types.hal b/confirmationui/1.0/types.hal
new file mode 100644
index 0000000..fd7ae6a
--- /dev/null
+++ b/confirmationui/1.0/types.hal
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.confirmationui@1.0;
+
+/**
+ * UI modification options.
+ */
+enum UIOption : uint32_t {
+    /** Accessibility: Requests color inverted style. */
+    AccessibilityInverted = 0,
+    /** Accessibility: Requests magnified style. */
+    AccessibilityMagnified = 1,
+};
+
+/**
+ * Codes returned by ConfirmationUI API calls.
+ */
+enum ResponseCode : uint32_t {
+    /** API call succeeded or the user gave approval (result callback). */
+    OK = 0,
+    /** The user canceled the TUI (result callback). */
+    Canceled = 1,
+    /** IConfirmationUI::abort() was called. (result callback). */
+    Aborted = 2,
+    /** Cannot start another prompt. */
+    OperationPending = 3,
+    /** IConfirmationUI::deliverSecureInputEvent call was ingored. */
+    Ignored = 4,
+    /** An unexpected system error occured. */
+    SystemError = 5,
+    /** Returned by an unimplemented API call. */
+    Unimplemented = 6,
+     /**
+       * This is returned when an error is diagnosed that should have been
+       * caught by earlier input sanitization. Should never be seen in production.
+       */
+    Unexpected = 7,
+    /** General UI error. */
+    UIError = 0x10000,
+    UIErrorMissingGlyph,
+    /**
+     * The implementation must return this error code on promptUserConfirmation if the
+     * resulting formatted message does not fit into MessageSize::MAX bytes. It is
+     * advised that the implementation formats the message upon receiving this API call to
+     * be able to diagnose this syndrome.
+     */
+    UIErrorMessageTooLong,
+    UIErrorMalformedUTF8Encoding,
+};
+
+/**
+ * This defines the maximum message size. This indirectly limits the size of the prompt text
+ * and the extra data that can be passed to the confirmation UI. The prompt text and extra data
+ * must fit in to this size including CBOR header information.
+ */
+enum MessageSize : uint32_t { MAX = 0x1800 };
+
+/**
+ * The test key is 32byte word with all bytes set to TestKeyBits::BYTE.
+ */
+enum TestKeyBits: uint8_t { BYTE = 0xA5 };
+
+/**
+ * Test mode commands.
+ *
+ * IConfirmationUI::deliverSecureInputEvent can be used to test certain code paths.
+ * To that end, the caller passes an auth token that has an HMAC keyed with the test key
+ * (see TestKeyBits in types.hal). Implementations first check the HMAC against test key.
+ * If the test key produces a matching HMAC, the implementation evaluates the challenge field
+ * of the auth token against the values defined in TestModeCommand.
+ * If the command indicates that a confirmation token is to be generated the test key MUST be used
+ * to generate this confirmation token.
+ *
+ * See command code for individual test command descriptions.
+ */
+enum TestModeCommands: uint64_t {
+    /**
+     * Simulates the user pressing the OK button on the UI. If no operation is pending
+     * ResponseCode::Ignored must be returned. A pending operation is finalized successfully
+     * see IConfirmationResultCallback::result, however, the test key (see TestKeyBits) MUST be
+     * used to generate the confirmation token.
+     */
+    OK_EVENT = 0,
+    /**
+     * Simulates the user pressing the CANCEL button on the UI. If no operation is pending
+     * Result::Ignored must be returned. A pending operation is finalized as specified in
+     * IConfirmationResultCallback.hal.
+     */
+    CANCEL_EVENT = 1,
+};
diff --git a/confirmationui/support/Android.bp b/confirmationui/support/Android.bp
new file mode 100644
index 0000000..62156b3
--- /dev/null
+++ b/confirmationui/support/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library {
+    name: "android.hardware.confirmationui-support-lib",
+    vendor_available: true,
+    host_supported: true,
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "src/cbor.cpp",
+        "src/confirmationui_utils.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ]
+}
+
+cc_test {
+    name: "android.hardware.confirmationui-support-lib-tests",
+    srcs: [
+        "test/gtest_main.cpp",
+        "test/android_cbor_test.cpp",
+        "test/msg_formatting_test.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+        "android.hardware.confirmationui-support-lib",
+    ],
+    shared_libs: [
+        "android.hardware.confirmationui@1.0",
+        "android.hardware.keymaster@4.0",
+        "libhidlbase",
+    ],
+    clang: true,
+    cflags: [ "-O0" ],
+}
diff --git a/confirmationui/support/OWNERS b/confirmationui/support/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/confirmationui/support/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/confirmationui/support/include/android/hardware/confirmationui/1.0/generic/GenericOperation.h b/confirmationui/support/include/android/hardware/confirmationui/1.0/generic/GenericOperation.h
new file mode 100644
index 0000000..a88cd40
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/1.0/generic/GenericOperation.h
@@ -0,0 +1,188 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_DEFAULT_GENERICOPERATION_H_
+#define CONFIRMATIONUI_1_0_DEFAULT_GENERICOPERATION_H_
+
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/hardware/confirmationui/support/cbor.h>
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+#include <android/hardware/keymaster/4.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace generic {
+
+namespace {
+using namespace ::android::hardware::confirmationui::support;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType;
+
+inline bool hasOption(UIOption option, const hidl_vec<UIOption>& uiOptions) {
+    for (auto& o : uiOptions) {
+        if (o == option) return true;
+    }
+    return false;
+}
+
+template <typename Callback, typename TimeStamper, typename HmacImplementation>
+class Operation {
+    using HMacer = support::HMac<HmacImplementation>;
+
+   public:
+    Operation() : error_(ResponseCode::Ignored), formattedMessageLength_(0) {}
+
+    ResponseCode init(const Callback& resultCB, const hidl_string& promptText,
+                      const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
+                      const hidl_vec<UIOption>& uiOptions) {
+        (void)locale;
+        (void)uiOptions;
+        resultCB_ = resultCB;
+        if (error_ != ResponseCode::Ignored) return ResponseCode::OperationPending;
+        // TODO make copy of promptText before using it may reside in shared buffer
+        auto state = write(
+            WriteState(formattedMessageBuffer_),
+            map(pair(text("prompt"), text(promptText)), pair(text("extra"), bytes(extraData))));
+        switch (state.error_) {
+            case Error::OK:
+                break;
+            case Error::OUT_OF_DATA:
+                return ResponseCode::UIErrorMessageTooLong;
+            case Error::MALFORMED_UTF8:
+                return ResponseCode::UIErrorMalformedUTF8Encoding;
+            case Error::MALFORMED:
+            default:
+                return ResponseCode::Unexpected;
+        }
+        formattedMessageLength_ = state.data_ - formattedMessageBuffer_;
+        // setup TUI and diagnose more UI errors here.
+        // on success record the start time
+        startTime_ = TimeStamper::now();
+        if (!startTime_.isOk()) {
+            return ResponseCode::SystemError;
+        }
+        error_ = ResponseCode::OK;
+        return ResponseCode::OK;
+    }
+
+    void setHmacKey(const uint8_t (&key)[32]) { hmacKey_ = {key}; }
+
+    void abort() {
+        // tear down TUI here
+        if (isPending()) {
+            resultCB_->result(ResponseCode::Aborted, {}, {});
+            error_ = ResponseCode::Ignored;
+        }
+    }
+
+    void userCancel() {
+        // tear down TUI here
+        if (isPending()) error_ = ResponseCode::Canceled;
+    }
+
+    void finalize(const uint8_t key[32]) {
+        if (error_ == ResponseCode::Ignored) return;
+        resultCB_->result(error_, getMessage(), userConfirm(key));
+        error_ = ResponseCode::Ignored;
+        resultCB_ = {};
+    }
+
+    bool isPending() const { return error_ != ResponseCode::Ignored; }
+
+    static Operation& get() {
+        static Operation operation;
+        return operation;
+    }
+
+    ResponseCode deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) {
+        constexpr uint8_t testKeyByte = static_cast<uint8_t>(TestKeyBits::BYTE);
+        constexpr uint8_t testKey[32] = {testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+                                         testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+                                         testKeyByte, testKeyByte, testKeyByte, testKeyByte,
+                                         testKeyByte, testKeyByte, testKeyByte, testKeyByte};
+
+        auto hmac = HMacer::hmac256(testKey, "\0", bytes_cast(secureInputToken.challenge),
+                                    bytes_cast(secureInputToken.userId),
+                                    bytes_cast(secureInputToken.authenticatorId),
+                                    bytes_cast(hton(secureInputToken.authenticatorType)),
+                                    bytes_cast(hton(secureInputToken.timestamp)));
+        if (!hmac.isOk()) return ResponseCode::Unexpected;
+        if (hmac.value() == secureInputToken.mac) {
+            // okay so this is a test token
+            switch (static_cast<TestModeCommands>(secureInputToken.challenge)) {
+                case TestModeCommands::OK_EVENT: {
+                    if (isPending()) {
+                        finalize(testKey);
+                        return ResponseCode::OK;
+                    } else {
+                        return ResponseCode::Ignored;
+                    }
+                }
+                case TestModeCommands::CANCEL_EVENT: {
+                    bool ignored = !isPending();
+                    userCancel();
+                    finalize(testKey);
+                    return ignored ? ResponseCode::Ignored : ResponseCode::OK;
+                }
+                default:
+                    return ResponseCode::Ignored;
+            }
+        }
+        return ResponseCode::Ignored;
+    }
+
+   private:
+    bool acceptAuthToken(const HardwareAuthToken&) { return false; }
+    hidl_vec<uint8_t> getMessage() {
+        hidl_vec<uint8_t> result;
+        if (error_ != ResponseCode::OK) return {};
+        result.setToExternal(formattedMessageBuffer_, formattedMessageLength_);
+        return result;
+    }
+    hidl_vec<uint8_t> userConfirm(const uint8_t key[32]) {
+        // tear down TUI here
+        if (error_ != ResponseCode::OK) return {};
+        confirmationTokenScratchpad_ = HMacer::hmac256(key, "confirmation token", getMessage());
+        if (!confirmationTokenScratchpad_.isOk()) {
+            error_ = ResponseCode::Unexpected;
+            return {};
+        }
+        hidl_vec<uint8_t> result;
+        result.setToExternal(confirmationTokenScratchpad_->data(),
+                             confirmationTokenScratchpad_->size());
+        return result;
+    }
+
+    ResponseCode error_;
+    uint8_t formattedMessageBuffer_[uint32_t(MessageSize::MAX)];
+    size_t formattedMessageLength_;
+    NullOr<array<uint8_t, 32>> confirmationTokenScratchpad_;
+    Callback resultCB_;
+    typename TimeStamper::TimeStamp startTime_;
+    NullOr<array<uint8_t, 32>> hmacKey_;
+};
+
+}  // namespace
+}  // namespace generic
+}  // namespace V1_0
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_DEFAULT_GENERICOPERATION_H_
diff --git a/confirmationui/support/include/android/hardware/confirmationui/support/cbor.h b/confirmationui/support/include/android/hardware/confirmationui/support/cbor.h
new file mode 100644
index 0000000..f5814d4
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/support/cbor.h
@@ -0,0 +1,335 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
+#define CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <type_traits>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+template <typename In, typename Out>
+Out copy(In begin, In end, Out out) {
+    while (begin != end) {
+        *out++ = *begin++;
+    }
+    return out;
+}
+
+enum class Type : uint8_t {
+    NUMBER = 0,
+    NEGATIVE = 1,
+    BYTE_STRING = 2,
+    TEXT_STRING = 3,
+    ARRAY = 4,
+    MAP = 5,
+    TAG = 6,
+    FLOAT = 7,
+};
+
+enum class Error : uint32_t {
+    OK = 0,
+    OUT_OF_DATA = 1,
+    MALFORMED = 2,
+    MALFORMED_UTF8 = 3,
+};
+
+template <typename Key, typename Value>
+struct MapElement {
+    const Key& key_;
+    const Value& value_;
+    MapElement(const Key& key, const Value& value) : key_(key), value_(value) {}
+};
+
+template <typename... Elems>
+struct Array;
+
+template <typename Head, typename... Tail>
+struct Array<Head, Tail...> {
+    const Head& head_;
+    Array<Tail...> tail_;
+    Array(const Head& head, const Tail&... tail) : head_(head), tail_(tail...) {}
+    constexpr size_t size() const { return sizeof...(Tail) + 1; };
+};
+
+template <>
+struct Array<> {};
+
+struct TextStr {};
+struct ByteStr {};
+
+template <typename T, typename Variant>
+struct StringBuffer {
+    const T* data_;
+    size_t size_;
+    StringBuffer(const T* data, size_t size) : data_(data), size_(size) {
+        static_assert(sizeof(T) == 1, "elements too large");
+    }
+    const T* data() const { return data_; }
+    size_t size() const { return size_; }
+};
+
+/**
+ * Takes a char array turns it into a StringBuffer of TextStr type. The length of the resulting
+ * StringBuffer is size - 1, effectively stripping the 0 character from the region being considered.
+ * If the terminating 0 shall not be stripped use text_keep_last.
+ */
+template <size_t size>
+StringBuffer<char, TextStr> text(const char (&str)[size]) {
+    if (size > 0) return StringBuffer<char, TextStr>(str, size - 1);
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+/**
+ * As opposed to text(const char (&str)[size] this function does not strips the last character.
+ */
+template <size_t size>
+StringBuffer<char, TextStr> text_keep_last(const char (&str)[size]) {
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+template <typename T>
+auto getData(const T& v) -> decltype(v.data()) {
+    return v.data();
+}
+
+template <typename T>
+auto getData(const T& v) -> decltype(v.c_str()) {
+    return v.c_str();
+}
+
+template <typename T>
+auto text(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr> {
+    return StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr>(getData(str), str.size());
+}
+
+inline StringBuffer<char, TextStr> text(const char* str, size_t size) {
+    return StringBuffer<char, TextStr>(str, size);
+}
+
+template <typename T, size_t size>
+StringBuffer<T, ByteStr> bytes(const T (&str)[size]) {
+    return StringBuffer<T, ByteStr>(str, size);
+}
+
+template <typename T>
+StringBuffer<T, ByteStr> bytes(const T* str, size_t size) {
+    return StringBuffer<T, ByteStr>(str, size);
+}
+
+template <typename T>
+auto bytes(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr> {
+    return StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr>(getData(str), str.size());
+}
+
+template <typename... Elems>
+struct Map;
+
+template <typename HeadKey, typename HeadValue, typename... Tail>
+struct Map<MapElement<HeadKey, HeadValue>, Tail...> {
+    const MapElement<HeadKey, HeadValue>& head_;
+    Map<Tail...> tail_;
+    Map(const MapElement<HeadKey, HeadValue>& head, const Tail&... tail)
+        : head_(head), tail_(tail...) {}
+    constexpr size_t size() const { return sizeof...(Tail) + 1; };
+};
+
+template <>
+struct Map<> {};
+
+template <typename... Keys, typename... Values>
+Map<MapElement<Keys, Values>...> map(const MapElement<Keys, Values>&... elements) {
+    return Map<MapElement<Keys, Values>...>(elements...);
+}
+
+template <typename... Elements>
+Array<Elements...> arr(const Elements&... elements) {
+    return Array<Elements...>(elements...);
+}
+
+template <typename Key, typename Value>
+MapElement<Key, Value> pair(const Key& k, const Value& v) {
+    return MapElement<Key, Value>(k, v);
+}
+
+template <size_t size>
+struct getUnsignedType;
+
+template <>
+struct getUnsignedType<sizeof(uint8_t)> {
+    typedef uint8_t type;
+};
+template <>
+struct getUnsignedType<sizeof(uint16_t)> {
+    typedef uint16_t type;
+};
+template <>
+struct getUnsignedType<sizeof(uint32_t)> {
+    typedef uint32_t type;
+};
+template <>
+struct getUnsignedType<sizeof(uint64_t)> {
+    typedef uint64_t type;
+};
+
+template <size_t size>
+using Unsigned = typename getUnsignedType<size>::type;
+
+class WriteState {
+   public:
+    WriteState() : data_(nullptr), size_(0), error_(Error::OK) {}
+    WriteState(uint8_t* buffer, size_t size) : data_(buffer), size_(size), error_(Error::OK) {}
+    WriteState(uint8_t* buffer, size_t size, Error error)
+        : data_(buffer), size_(size), error_(error) {}
+    template <size_t size>
+    WriteState(uint8_t (&buffer)[size]) : data_(buffer), size_(size), error_(Error::OK) {}
+
+    WriteState& operator++() {
+        if (size_) {
+            ++data_;
+            --size_;
+        } else {
+            error_ = Error::OUT_OF_DATA;
+        }
+        return *this;
+    }
+    WriteState& operator+=(size_t offset) {
+        if (offset > size_) {
+            error_ = Error::OUT_OF_DATA;
+        } else {
+            data_ += offset;
+            size_ -= offset;
+        }
+        return *this;
+    }
+    operator bool() const { return error_ == Error::OK; }
+
+    uint8_t* data_;
+    size_t size_;
+    Error error_;
+};
+
+WriteState writeHeader(WriteState wState, Type type, const uint64_t value);
+bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out);
+
+template <typename T>
+WriteState writeNumber(WriteState wState, const T& v) {
+    if (!wState) return wState;
+    if (v >= 0) {
+        return writeHeader(wState, Type::NUMBER, v);
+    } else {
+        return writeHeader(wState, Type::NEGATIVE, UINT64_C(-1) - v);
+    }
+}
+
+inline WriteState write(const WriteState& wState, const uint8_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int8_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint16_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int16_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint32_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int32_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const uint64_t& v) {
+    return writeNumber(wState, v);
+}
+inline WriteState write(const WriteState& wState, const int64_t& v) {
+    return writeNumber(wState, v);
+}
+
+template <typename T>
+WriteState write(WriteState wState, const StringBuffer<T, TextStr>& v) {
+    wState = writeHeader(wState, Type::TEXT_STRING, v.size());
+    uint8_t* buffer = wState.data_;
+    wState += v.size();
+    if (!wState) return wState;
+    if (!checkUTF8Copy(v.data(), v.data() + v.size(), buffer)) {
+        wState.error_ = Error::MALFORMED_UTF8;
+    }
+    return wState;
+}
+
+template <typename T>
+WriteState write(WriteState wState, const StringBuffer<T, ByteStr>& v) {
+    wState = writeHeader(wState, Type::BYTE_STRING, v.size());
+    uint8_t* buffer = wState.data_;
+    wState += v.size();
+    if (!wState) return wState;
+    static_assert(sizeof(*v.data()) == 1, "elements too large");
+    copy(v.data(), v.data() + v.size(), buffer);
+    return wState;
+}
+
+template <template <typename...> class Arr>
+WriteState writeArrayHelper(WriteState wState, const Arr<>&) {
+    return wState;
+}
+
+template <template <typename...> class Arr, typename Head, typename... Tail>
+WriteState writeArrayHelper(WriteState wState, const Arr<Head, Tail...>& arr) {
+    wState = write(wState, arr.head_);
+    return writeArrayHelper(wState, arr.tail_);
+}
+
+template <typename... Elems>
+WriteState write(WriteState wState, const Map<Elems...>& map) {
+    if (!wState) return wState;
+    wState = writeHeader(wState, Type::MAP, map.size());
+    return writeArrayHelper(wState, map);
+}
+
+template <typename... Elems>
+WriteState write(WriteState wState, const Array<Elems...>& arr) {
+    if (!wState) return wState;
+    wState = writeHeader(wState, Type::ARRAY, arr.size());
+    return writeArrayHelper(wState, arr);
+}
+
+template <typename Key, typename Value>
+WriteState write(WriteState wState, const MapElement<Key, Value>& element) {
+    if (!wState) return wState;
+    wState = write(wState, element.key_);
+    return write(wState, element.value_);
+}
+
+template <typename Head, typename... Tail>
+WriteState write(WriteState wState, const Head& head, const Tail&... tail) {
+    wState = write(wState, head);
+    return write(wState, tail...);
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
diff --git a/confirmationui/support/include/android/hardware/confirmationui/support/confirmationui_utils.h b/confirmationui/support/include/android/hardware/confirmationui/support/confirmationui_utils.h
new file mode 100644
index 0000000..d551433
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/support/confirmationui_utils.h
@@ -0,0 +1,213 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_
+#define CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <initializer_list>
+#include <type_traits>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+/**
+ * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
+ * of band. Note that if the wrapped value is a reference it is unsafe to access the value if
+ * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
+ * wrapped value. In this case the pointer will be NULL though, and the value will be default
+ * constructed.
+ */
+template <typename ValueT>
+class NullOr {
+    template <typename T>
+    struct reference_initializer {
+        static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
+    };
+    template <typename T>
+    struct pointer_initializer {
+        static T init() { return nullptr; }
+    };
+    template <typename T>
+    struct value_initializer {
+        static T init() { return T(); }
+    };
+    template <typename T>
+    using initializer_t =
+        std::conditional_t<std::is_lvalue_reference<T>::value, reference_initializer<T>,
+                           std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>,
+                                              value_initializer<T>>>;
+
+   public:
+    NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
+    NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}
+
+    bool isOk() const { return !null_; }
+
+    const ValueT& value() const & { return value_; }
+    ValueT& value() & { return value_; }
+    ValueT&& value() && { return std::move(value_); }
+
+    const std::remove_reference_t<ValueT>* operator->() const { return &value_; }
+    std::remove_reference_t<ValueT>* operator->() { return &value_; }
+
+   private:
+    ValueT value_;
+    bool null_;
+};
+
+template <typename T, size_t elements>
+class array {
+    using array_type = T[elements];
+
+   public:
+    array() : data_{} {}
+    array(const T (&data)[elements]) { std::copy(data, data + elements, data_); }
+
+    T* data() { return data_; }
+    const T* data() const { return data_; }
+    constexpr size_t size() const { return elements; }
+    operator const array_type&() const { return data_; }
+
+    T* begin() { return data_; }
+    T* end() { return data_ + elements; }
+    const T* begin() const { return data_; }
+    const T* end() const { return data_ + elements; }
+
+   private:
+    array_type data_;
+};
+
+template <typename T>
+auto bytes_cast(const T& v) -> const uint8_t (&)[sizeof(T)] {
+    return *reinterpret_cast<const uint8_t(*)[sizeof(T)]>(&v);
+}
+template <typename T>
+auto bytes_cast(T& v) -> uint8_t (&)[sizeof(T)] {
+    return *reinterpret_cast<uint8_t(*)[sizeof(T)]>(&v);
+}
+
+class ByteBufferProxy {
+    template <typename T>
+    struct has_data {
+        template <typename U>
+        static int f(const U*, const void*) {
+            return 0;
+        }
+        template <typename U>
+        static int* f(const U* u, decltype(u->data())) {
+            return nullptr;
+        }
+        static constexpr bool value = std::is_pointer<decltype(f((T*)nullptr, ""))>::value;
+    };
+
+   public:
+    template <typename T>
+    ByteBufferProxy(const T& buffer, decltype(buffer.data()) = nullptr)
+        : data_(reinterpret_cast<const uint8_t*>(buffer.data())), size_(buffer.size()) {
+        static_assert(sizeof(decltype(*buffer.data())) == 1, "elements to large");
+    }
+
+    // this overload kicks in for types that have .c_str() but not .data(), such as hidl_string.
+    // std::string has both so we need to explicitly disable this overload if .data() is present.
+    template <typename T>
+    ByteBufferProxy(const T& buffer,
+                    std::enable_if_t<!has_data<T>::value, decltype(buffer.c_str())> = nullptr)
+        : data_(reinterpret_cast<const uint8_t*>(buffer.c_str())), size_(buffer.size()) {
+        static_assert(sizeof(decltype(*buffer.c_str())) == 1, "elements to large");
+    }
+
+    template <size_t size>
+    ByteBufferProxy(const char (&buffer)[size])
+        : data_(reinterpret_cast<const uint8_t*>(buffer)), size_(size - 1) {
+        static_assert(size > 0, "even an empty string must be 0-terminated");
+    }
+
+    template <size_t size>
+    ByteBufferProxy(const uint8_t (&buffer)[size]) : data_(buffer), size_(size) {}
+
+    ByteBufferProxy() : data_(nullptr), size_(0) {}
+
+    const uint8_t* data() const { return data_; }
+    size_t size() const { return size_; }
+
+    const uint8_t* begin() const { return data_; }
+    const uint8_t* end() const { return data_ + size_; }
+
+   private:
+    const uint8_t* data_;
+    size_t size_;
+};
+
+/**
+ * Implementer are expected to provide an implementation with the following prototype:
+ *  static NullOr<array<uint8_t, 32>> hmac256(const uint8_t key[32],
+ *                                     std::initializer_list<ByteBufferProxy> buffers);
+ */
+template <typename Impl>
+class HMac {
+   public:
+    template <typename... Data>
+    static NullOr<array<uint8_t, 32>> hmac256(const uint8_t key[32], const Data&... data) {
+        return Impl::hmac256(key, {data...});
+    }
+};
+
+bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs);
+
+template <typename IntType, uint32_t byteOrder>
+struct choose_hton;
+
+template <typename IntType>
+struct choose_hton<IntType, __ORDER_LITTLE_ENDIAN__> {
+    inline static IntType hton(const IntType& value) {
+        IntType result = {};
+        const unsigned char* inbytes = reinterpret_cast<const unsigned char*>(&value);
+        unsigned char* outbytes = reinterpret_cast<unsigned char*>(&result);
+        for (int i = sizeof(IntType) - 1; i >= 0; --i) {
+            *(outbytes++) = inbytes[i];
+        }
+        return result;
+    }
+};
+
+template <typename IntType>
+struct choose_hton<IntType, __ORDER_BIG_ENDIAN__> {
+    inline static IntType hton(const IntType& value) { return value; }
+};
+
+template <typename IntType>
+inline IntType hton(const IntType& value) {
+    return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
+template <typename IntType>
+inline IntType ntoh(const IntType& value) {
+    // same operation as hton
+    return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_1_0_SUPPORT_INCLUDE_CONFIRMATIONUI_UTILS_H_
diff --git a/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h b/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h
new file mode 100644
index 0000000..0d03591
--- /dev/null
+++ b/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h
@@ -0,0 +1,471 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
+#define CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
+
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <algorithm>
+#include <tuple>
+#include <type_traits>
+
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+template <size_t... I>
+class IntegerSequence {};
+
+namespace integer_sequence {
+
+template <typename Lhs, typename Rhs>
+struct conc {};
+
+template <size_t... ILhs, size_t... IRhs>
+struct conc<IntegerSequence<ILhs...>, IntegerSequence<IRhs...>> {
+    using type = IntegerSequence<ILhs..., IRhs...>;
+};
+
+template <typename Lhs, typename Rhs>
+using conc_t = typename conc<Lhs, Rhs>::type;
+
+template <size_t... n>
+struct make {};
+
+template <size_t n>
+struct make<n> {
+    using type = conc_t<typename make<n - 1>::type, IntegerSequence<n - 1>>;
+};
+template <size_t start, size_t n>
+struct make<start, n> {
+    using type = conc_t<typename make<start, n - 1>::type, IntegerSequence<start + n - 1>>;
+};
+
+template <size_t start>
+struct make<start, start> {
+    using type = IntegerSequence<start>;
+};
+
+template <>
+struct make<0> {
+    using type = IntegerSequence<>;
+};
+
+template <size_t... n>
+using make_t = typename make<n...>::type;
+
+}  // namespace integer_sequence
+
+template <size_t... idx, typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move_helper(IntegerSequence<idx...>,
+                                                              std::tuple<T...>&& t) {
+    return {std::move(std::get<idx>(t))...};
+}
+
+template <typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>&& t) {
+    return tuple_move_helper(integer_sequence::make_t<sizeof...(T)>(), std::move(t));
+}
+
+template <typename... T>
+std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>& t) {
+    return tuple_move_helper(integer_sequence::make_t<sizeof...(T)>(), std::move(t));
+}
+
+using ::android::hardware::confirmationui::V1_0::ResponseCode;
+using ::android::hardware::confirmationui::V1_0::UIOption;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+template <typename... fields>
+class Message {};
+
+enum class Command : uint32_t {
+    PromptUserConfirmation,
+    DeliverSecureInputEvent,
+    Abort,
+};
+
+template <Command cmd>
+struct Cmd {};
+
+#define DECLARE_COMMAND(cmd) using cmd##_t = Cmd<Command::cmd>
+
+DECLARE_COMMAND(PromptUserConfirmation);
+DECLARE_COMMAND(DeliverSecureInputEvent);
+DECLARE_COMMAND(Abort);
+
+using PromptUserConfirmationMsg = Message<PromptUserConfirmation_t, hidl_string, hidl_vec<uint8_t>,
+                                          hidl_string, hidl_vec<UIOption>>;
+using PromptUserConfirmationResponse = Message<ResponseCode>;
+using DeliverSecureInputEventMsg = Message<DeliverSecureInputEvent_t, HardwareAuthToken>;
+using DeliverSecureInputEventRespose = Message<ResponseCode>;
+using AbortMsg = Message<Abort_t>;
+using ResultMsg = Message<ResponseCode, hidl_vec<uint8_t>, hidl_vec<uint8_t>>;
+
+template <typename T>
+struct StreamState {
+    using ptr_t = volatile T*;
+    volatile T* pos_;
+    size_t bytes_left_;
+    bool good_;
+    template <size_t size>
+    StreamState(T (&buffer)[size]) : pos_(buffer), bytes_left_(size), good_(size > 0) {}
+    StreamState(T* buffer, size_t size) : pos_(buffer), bytes_left_(size), good_(size > 0) {}
+    StreamState() : pos_(nullptr), bytes_left_(0), good_(false) {}
+    StreamState& operator++() {
+        if (good_ && bytes_left_) {
+            ++pos_;
+            --bytes_left_;
+        } else {
+            good_ = false;
+        }
+        return *this;
+    }
+    StreamState& operator+=(size_t offset) {
+        if (!good_ || offset > bytes_left_) {
+            good_ = false;
+        } else {
+            pos_ += offset;
+            bytes_left_ -= offset;
+        }
+        return *this;
+    }
+    operator bool() const { return good_; }
+    volatile T* pos() const { return pos_; };
+};
+
+using WriteStream = StreamState<uint8_t>;
+using ReadStream = StreamState<const uint8_t>;
+
+inline void zero(volatile uint8_t* begin, const volatile uint8_t* end) {
+    while (begin != end) {
+        *begin++ = 0xaa;
+    }
+}
+inline void zero(const volatile uint8_t*, const volatile uint8_t*) {}
+// This odd alignment function aligns the stream position to a 4byte and never 8byte boundary
+// It is to accommodate the 4 byte size field which is then followed by 8byte alligned data.
+template <typename T>
+StreamState<T> unalign(StreamState<T> s) {
+    uint8_t unalignment = uintptr_t(s.pos_) & 0x3;
+    auto pos = s.pos_;
+    if (unalignment) {
+        s += 4 - unalignment;
+    }
+    // now s.pos_ is aligned on a 4byte boundary
+    if ((uintptr_t(s.pos_) & 0x4) == 0) {
+        // if we are 8byte aligned add 4
+        s += 4;
+    }
+    // zero out the gaps when writing
+    zero(pos, s.pos_);
+    return s;
+}
+
+inline WriteStream write(WriteStream out, const uint8_t* buffer, size_t size) {
+    auto pos = out.pos();
+    uint32_t v = size;
+    out += 4 + size;
+    if (out) {
+        if (size != v) {
+            out.good_ = false;
+            return out;
+        }
+        auto& s = bytes_cast(v);
+        pos = std::copy(s, s + 4, pos);
+        std::copy(buffer, buffer + size, pos);
+    }
+    return out;
+}
+template <size_t size>
+WriteStream write(WriteStream out, const uint8_t (&v)[size]) {
+    return write(out, v, size);
+}
+
+inline std::tuple<ReadStream, ReadStream::ptr_t, size_t> read(ReadStream in) {
+    auto pos = in.pos();
+    in += 4;
+    if (!in) return {in, nullptr, 0};
+    uint32_t size;
+    std::copy(pos, pos + 4, bytes_cast(size));
+    pos = in.pos();
+    in += size;
+    if (!in) return {in, nullptr, 0};
+    return {in, pos, size};
+}
+
+template <typename T>
+std::tuple<ReadStream, T> readSimpleType(ReadStream in) {
+    T result;
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(in, pos, read_size) = read(in);
+    if (!in || read_size != sizeof(T)) {
+        in.good_ = false;
+        return {in, {}};
+    }
+    std::copy(pos, pos + sizeof(T), bytes_cast(result));
+    return {in, std::move(result)};
+}
+
+template <typename T>
+std::tuple<ReadStream, hidl_vec<T>> readSimpleHidlVecInPlace(ReadStream in) {
+    std::tuple<ReadStream, hidl_vec<T>> result;
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(std::get<0>(result), pos, read_size) = read(in);
+    if (!std::get<0>(result) || read_size % sizeof(T)) {
+        std::get<0>(result).good_ = false;
+        return result;
+    }
+    std::get<1>(result).setToExternal(reinterpret_cast<T*>(const_cast<uint8_t*>(pos)),
+                                      read_size / sizeof(T));
+    return result;
+}
+
+template <typename T>
+WriteStream writeSimpleHidlVec(WriteStream out, const hidl_vec<T>& vec) {
+    return write(out, reinterpret_cast<const uint8_t*>(vec.data()), vec.size() * sizeof(T));
+}
+
+// HardwareAuthToken
+constexpr size_t hatSizeNoMac() {
+    HardwareAuthToken* hat = nullptr;
+    return sizeof hat->challenge + sizeof hat->userId + sizeof hat->authenticatorId +
+           sizeof hat->authenticatorType + sizeof hat->timestamp;
+}
+
+template <typename T>
+inline volatile const uint8_t* copyField(T& field, volatile const uint8_t*(&pos)) {
+    auto& s = bytes_cast(field);
+    std::copy(pos, pos + sizeof(T), s);
+    return pos + sizeof(T);
+}
+inline std::tuple<ReadStream, HardwareAuthToken> read(Message<HardwareAuthToken>, ReadStream in_) {
+    std::tuple<ReadStream, HardwareAuthToken> result;
+    ReadStream& in = std::get<0>(result) = in_;
+    auto& hat = std::get<1>(result);
+    constexpr size_t hatSize = hatSizeNoMac();
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(in, pos, read_size) = read(in);
+    if (!in || read_size != hatSize) {
+        in.good_ = false;
+        return result;
+    }
+    pos = copyField(hat.challenge, pos);
+    pos = copyField(hat.userId, pos);
+    pos = copyField(hat.authenticatorId, pos);
+    pos = copyField(hat.authenticatorType, pos);
+    pos = copyField(hat.timestamp, pos);
+    std::tie(in, hat.mac) = readSimpleHidlVecInPlace<uint8_t>(in);
+    return result;
+}
+
+template <typename T>
+inline volatile uint8_t* copyField(const T& field, volatile uint8_t*(&pos)) {
+    auto& s = bytes_cast(field);
+    return std::copy(s, &s[sizeof(T)], pos);
+}
+
+inline WriteStream write(WriteStream out, const HardwareAuthToken& v) {
+    auto pos = out.pos();
+    uint32_t size_field = hatSizeNoMac();
+    out += 4 + size_field;
+    if (!out) return out;
+    pos = copyField(size_field, pos);
+    pos = copyField(v.challenge, pos);
+    pos = copyField(v.userId, pos);
+    pos = copyField(v.authenticatorId, pos);
+    pos = copyField(v.authenticatorType, pos);
+    pos = copyField(v.timestamp, pos);
+    return writeSimpleHidlVec(out, v.mac);
+}
+
+// ResponseCode
+inline std::tuple<ReadStream, ResponseCode> read(Message<ResponseCode>, ReadStream in) {
+    return readSimpleType<ResponseCode>(in);
+}
+inline WriteStream write(WriteStream out, const ResponseCode& v) {
+    return write(out, bytes_cast(v));
+}
+
+// hidl_vec<uint8_t>
+inline std::tuple<ReadStream, hidl_vec<uint8_t>> read(Message<hidl_vec<uint8_t>>, ReadStream in) {
+    return readSimpleHidlVecInPlace<uint8_t>(in);
+}
+inline WriteStream write(WriteStream out, const hidl_vec<uint8_t>& v) {
+    return writeSimpleHidlVec(out, v);
+}
+
+// hidl_vec<UIOption>
+inline std::tuple<ReadStream, hidl_vec<UIOption>> read(Message<hidl_vec<UIOption>>, ReadStream in) {
+    in = unalign(in);
+    return readSimpleHidlVecInPlace<UIOption>(in);
+}
+inline WriteStream write(WriteStream out, const hidl_vec<UIOption>& v) {
+    out = unalign(out);
+    return writeSimpleHidlVec(out, v);
+}
+
+// hidl_string
+inline std::tuple<ReadStream, hidl_string> read(Message<hidl_string>, ReadStream in) {
+    std::tuple<ReadStream, hidl_string> result;
+    ReadStream& in_ = std::get<0>(result);
+    hidl_string& result_ = std::get<1>(result);
+    ReadStream::ptr_t pos = nullptr;
+    size_t read_size = 0;
+    std::tie(in_, pos, read_size) = read(in);
+    auto terminating_zero = in_.pos();
+    ++in_;  // skip the terminating zero. Does nothing if the stream was already bad
+    if (!in_) return result;
+    if (*terminating_zero) {
+        in_.good_ = false;
+        return result;
+    }
+    result_.setToExternal(reinterpret_cast<const char*>(const_cast<const uint8_t*>(pos)),
+                          read_size);
+    return result;
+}
+inline WriteStream write(WriteStream out, const hidl_string& v) {
+    out = write(out, reinterpret_cast<const uint8_t*>(v.c_str()), v.size());
+    auto terminating_zero = out.pos();
+    ++out;
+    if (out) {
+        *terminating_zero = 0;
+    }
+    return out;
+}
+
+inline WriteStream write(WriteStream out, Command cmd) {
+    volatile Command* pos = reinterpret_cast<volatile Command*>(out.pos_);
+    out += sizeof(Command);
+    if (out) {
+        *pos = cmd;
+    }
+    return out;
+}
+template <Command cmd>
+WriteStream write(WriteStream out, Cmd<cmd>) {
+    return write(out, cmd);
+}
+
+inline std::tuple<ReadStream, bool> read(ReadStream in, Command cmd) {
+    volatile const Command* pos = reinterpret_cast<volatile const Command*>(in.pos_);
+    in += sizeof(Command);
+    if (!in) return {in, false};
+    return {in, *pos == cmd};
+}
+
+template <Command cmd>
+std::tuple<ReadStream, bool> read(Message<Cmd<cmd>>, ReadStream in) {
+    return read(in, cmd);
+}
+
+inline WriteStream write(Message<>, WriteStream out) {
+    return out;
+}
+
+template <typename Head, typename... Tail>
+WriteStream write(Message<Head, Tail...>, WriteStream out, const Head& head, const Tail&... tail) {
+    out = write(out, head);
+    return write(Message<Tail...>(), out, tail...);
+}
+
+template <Command cmd, typename... Tail>
+WriteStream write(Message<Cmd<cmd>, Tail...>, WriteStream out, const Tail&... tail) {
+    out = write(out, cmd);
+    return write(Message<Tail...>(), out, tail...);
+}
+
+template <Command cmd, typename HEAD, typename... Tail>
+std::tuple<ReadStream, bool, HEAD, Tail...> read(Message<Cmd<cmd>, HEAD, Tail...>, ReadStream in) {
+    bool command_matches;
+    std::tie(in, command_matches) = read(in, cmd);
+    if (!command_matches) return {in, false, HEAD(), Tail()...};
+
+    return {in, true,
+            [&]() -> HEAD {
+                HEAD result;
+                std::tie(in, result) = read(Message<HEAD>(), in);
+                return result;
+            }(),
+            [&]() -> Tail {
+                Tail result;
+                std::tie(in, result) = read(Message<Tail>(), in);
+                return result;
+            }()...};
+}
+
+template <typename... Msg>
+std::tuple<ReadStream, Msg...> read(Message<Msg...>, ReadStream in) {
+    return {in, [&in]() -> Msg {
+                Msg result;
+                std::tie(in, result) = read(Message<Msg>(), in);
+                return result;
+            }()...};
+}
+
+template <typename T>
+struct msg2tuple {};
+
+template <typename... T>
+struct msg2tuple<Message<T...>> {
+    using type = std::tuple<T...>;
+};
+template <Command cmd, typename... T>
+struct msg2tuple<Message<Cmd<cmd>, T...>> {
+    using type = std::tuple<T...>;
+};
+
+template <typename T>
+using msg2tuple_t = typename msg2tuple<T>::type;
+
+template <size_t... idx, typename HEAD, typename... T>
+std::tuple<T&&...> tuple_tail(IntegerSequence<idx...>, std::tuple<HEAD, T...>&& t) {
+    return {std::move(std::get<idx>(t))...};
+}
+
+template <size_t... idx, typename HEAD, typename... T>
+std::tuple<const T&...> tuple_tail(IntegerSequence<idx...>, const std::tuple<HEAD, T...>& t) {
+    return {std::get<idx>(t)...};
+}
+
+template <typename HEAD, typename... Tail>
+std::tuple<Tail&&...> tuple_tail(std::tuple<HEAD, Tail...>&& t) {
+    return tuple_tail(integer_sequence::make_t<1, sizeof...(Tail)>(), std::move(t));
+}
+
+template <typename HEAD, typename... Tail>
+std::tuple<const Tail&...> tuple_tail(const std::tuple<HEAD, Tail...>& t) {
+    return tuple_tail(integer_sequence::make_t<1, sizeof...(Tail)>(), t);
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
+
+#endif  // CONFIRMATIONUI_SUPPORT_INCLUDE_ANDROID_HARDWARE_CONFIRMATIONUI_SUPPORT_MSG_FORMATTING_H_
diff --git a/confirmationui/support/src/cbor.cpp b/confirmationui/support/src/cbor.cpp
new file mode 100644
index 0000000..e7ea164
--- /dev/null
+++ b/confirmationui/support/src/cbor.cpp
@@ -0,0 +1,111 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <android/hardware/confirmationui/support/cbor.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+namespace {
+
+inline uint8_t getByte(const uint64_t& v, const uint8_t index) {
+    return v >> (index * 8);
+}
+
+WriteState writeBytes(WriteState state, uint64_t value, uint8_t size) {
+    auto pos = state.data_;
+    if (!(state += size)) return state;
+    switch (size) {
+        case 8:
+            *pos++ = getByte(value, 7);
+            *pos++ = getByte(value, 6);
+            *pos++ = getByte(value, 5);
+            *pos++ = getByte(value, 4);
+        case 4:
+            *pos++ = getByte(value, 3);
+            *pos++ = getByte(value, 2);
+        case 2:
+            *pos++ = getByte(value, 1);
+        case 1:
+            *pos++ = value;
+            break;
+        default:
+            state.error_ = Error::MALFORMED;
+    }
+    return state;
+}
+
+}  // anonymous namespace
+
+WriteState writeHeader(WriteState wState, Type type, const uint64_t value) {
+    if (!wState) return wState;
+    uint8_t& header = *wState.data_;
+    if (!++wState) return wState;
+    header = static_cast<uint8_t>(type) << 5;
+    if (value < 24) {
+        header |= static_cast<uint8_t>(value);
+    } else if (value < 0x100) {
+        header |= 24;
+        wState = writeBytes(wState, value, 1);
+    } else if (value < 0x10000) {
+        header |= 25;
+        wState = writeBytes(wState, value, 2);
+    } else if (value < 0x100000000) {
+        header |= 26;
+        wState = writeBytes(wState, value, 4);
+    } else {
+        header |= 27;
+        wState = writeBytes(wState, value, 8);
+    }
+    return wState;
+}
+
+bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out) {
+    uint32_t multi_byte_length = 0;
+    while (begin != end) {
+        if (multi_byte_length) {
+            // parsing multi byte character - must start with 10xxxxxx
+            --multi_byte_length;
+            if ((*begin & 0xc0) != 0x80) return false;
+        } else if (!((*begin) & 0x80)) {
+            // 7bit character -> nothing to be done
+        } else {
+            // msb is set and we were not parsing a multi byte character
+            // so this must be a header byte
+            char c = *begin << 1;
+            while (c & 0x80) {
+                ++multi_byte_length;
+                c <<= 1;
+            }
+            // headers of the form 10xxxxxx are not allowed
+            if (multi_byte_length < 1) return false;
+            // chars longer than 4 bytes are not allowed (multi_byte_length does not count the
+            // header thus > 3
+            if (multi_byte_length > 3) return false;
+        }
+        if (out) *out++ = *reinterpret_cast<const uint8_t*>(begin++);
+    }
+    // if the string ends in the middle of a multi byte char it is invalid
+    if (multi_byte_length) return false;
+    return true;
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/support/src/confirmationui_utils.cpp b/confirmationui/support/src/confirmationui_utils.cpp
new file mode 100644
index 0000000..708f0d56
--- /dev/null
+++ b/confirmationui/support/src/confirmationui_utils.cpp
@@ -0,0 +1,39 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <android/hardware/confirmationui/support/confirmationui_utils.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace support {
+
+bool operator==(const ByteBufferProxy& lhs, const ByteBufferProxy& rhs) {
+    if (lhs.size() == rhs.size()) {
+        auto lhsi = lhs.begin();
+        auto rhsi = rhs.begin();
+        while (lhsi != lhs.end()) {
+            if (*lhsi++ != *rhsi++) return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace support
+}  // namespace confirmationui
+}  // namespace hardware
+}  // namespace android
diff --git a/confirmationui/support/test/android_cbor_test.cpp b/confirmationui/support/test/android_cbor_test.cpp
new file mode 100644
index 0000000..4a5a362
--- /dev/null
+++ b/confirmationui/support/test/android_cbor_test.cpp
@@ -0,0 +1,197 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <android/hardware/confirmationui/support/cbor.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <iomanip>
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+using namespace android::hardware::confirmationui::support;
+
+uint8_t testVector[] = {
+    0xA4, 0x63, 0x6B, 0x65, 0x79, 0x65, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x63, 0x6B, 0x65, 0x79, 0x4D,
+    0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x31, 0x30, 0x00, 0x04, 0x07, 0x1B,
+    0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x07, 0x1A, 0xFD, 0x49, 0x8C, 0xFF,
+    0xFF, 0x82, 0x69, 0xE2, 0x99, 0xA8, 0xE2, 0x9A, 0x96, 0xE2, 0xB6, 0x96, 0x59, 0x01, 0x91, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61,
+    0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x00,
+};
+
+// 400 'a's and a '\0'
+constexpr char fourHundredAs[] =
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+    "aaaaaaaaaaaaaaaaaaaaaaaa";
+
+WriteState writeTest(WriteState state) {
+    return write(state,                                                     //
+                 map(                                                       //
+                     pair(text("key"), text("value")),                      //
+                     pair(text("key"), bytes("100101010010")),              //
+                     pair(4, 7),                                            //
+                     pair((UINT64_C(1) << 62), INT64_C(-2000000000000000))  //
+                     ),                                                     //
+                 arr(text("♨⚖ⶖ"), bytes(fourHundredAs)));
+}
+
+TEST(Cbor, FeatureTest) {
+    uint8_t buffer[0x1000];
+    WriteState state(buffer);
+    state = writeTest(state);
+    ASSERT_EQ(sizeof(testVector), size_t(state.data_ - buffer));
+    ASSERT_EQ(Error::OK, state.error_);
+    ASSERT_EQ(0, memcmp(buffer, testVector, sizeof(testVector)));
+}
+
+// Test if in all write cases an out of data error is correctly propagated and we don't
+// write beyond  the end of the buffer.
+TEST(Cbor, BufferTooShort) {
+    uint8_t buffer[0x1000];
+    for (size_t s = 1; s < sizeof(testVector); ++s) {
+        memset(buffer, 0x22, 0x1000);  // 0x22 is not in the testVector
+        WriteState state(buffer, s);
+        state = writeTest(state);
+        for (size_t t = s; t < 0x1000; ++t) {
+            ASSERT_EQ(0x22, buffer[t]);  // check if a canary has been killed
+        }
+        ASSERT_EQ(Error::OUT_OF_DATA, state.error_);
+    }
+}
+
+TEST(Cbor, MalformedUTF8Test_Stray) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0x80), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, MalformendUTF8Test_StringEndsMidMultiByte) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0xc0), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, UTF8Test_TwoBytes) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char neat[] = {char(0xc3), char(0x82), 0};
+    state = write(state, text(neat));
+    ASSERT_EQ(Error::OK, state.error_);
+}
+
+TEST(Cbor, UTF8Test_ThreeBytes) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char neat[] = {char(0xe3), char(0x82), char(0x82), 0};
+    state = write(state, text(neat));
+    ASSERT_EQ(Error::OK, state.error_);
+}
+
+TEST(Cbor, UTF8Test_FourBytes) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char neat[] = {char(0xf3), char(0x82), char(0x82), char(0x82), 0};
+    state = write(state, text(neat));
+    ASSERT_EQ(Error::OK, state.error_);
+}
+
+TEST(Cbor, MalformendUTF8Test_CharacterTooLong) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0xf8), char(0x82), char(0x82), char(0x82), char(0x82), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, MalformendUTF8Test_StringEndsMidMultiByte2) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    char malformed[] = {char(0xc0), char(0x82), char(0x83), 0};
+    state = write(state, text(malformed));
+    ASSERT_EQ(Error::MALFORMED_UTF8, state.error_);
+}
+
+TEST(Cbor, MinimalViableHeaderSizeTest) {
+    uint8_t buffer[20];
+    WriteState state(buffer);
+    state = writeHeader(state, Type::NUMBER, 23);
+    ASSERT_EQ(state.data_ - buffer, 1);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 24);
+    ASSERT_EQ(state.data_ - buffer, 2);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xff);
+    ASSERT_EQ(state.data_ - buffer, 2);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0x100);
+    ASSERT_EQ(state.data_ - buffer, 3);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xffff);
+    ASSERT_EQ(state.data_ - buffer, 3);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0x10000);
+    ASSERT_EQ(state.data_ - buffer, 5);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xffffffff);
+    ASSERT_EQ(state.data_ - buffer, 5);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0x100000000);
+    ASSERT_EQ(state.data_ - buffer, 9);
+
+    state = WriteState(buffer);
+    state = writeHeader(state, Type::NUMBER, 0xffffffffffffffff);
+    ASSERT_EQ(state.data_ - buffer, 9);
+}
diff --git a/confirmationui/support/test/gtest_main.cpp b/confirmationui/support/test/gtest_main.cpp
new file mode 100644
index 0000000..43fc5a3
--- /dev/null
+++ b/confirmationui/support/test/gtest_main.cpp
@@ -0,0 +1,23 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <gtest/gtest.h>
+
+int main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/confirmationui/support/test/msg_formatting_test.cpp b/confirmationui/support/test/msg_formatting_test.cpp
new file mode 100644
index 0000000..90ed84c
--- /dev/null
+++ b/confirmationui/support/test/msg_formatting_test.cpp
@@ -0,0 +1,128 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stddef.h>
+#include <stdint.h>
+#include <iomanip>
+#include <iostream>
+#include <string>
+
+#include <android/hardware/confirmationui/support/msg_formatting.h>
+#include <gtest/gtest.h>
+
+using android::hardware::confirmationui::support::Message;
+using android::hardware::confirmationui::support::WriteStream;
+using android::hardware::confirmationui::support::ReadStream;
+using android::hardware::confirmationui::support::PromptUserConfirmationMsg;
+using android::hardware::confirmationui::support::write;
+using ::android::hardware::confirmationui::V1_0::UIOption;
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+#ifdef DEBUG_MSG_FORMATTING
+namespace {
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+std::ostream& hexdump(std::ostream& out, const uint8_t* data, size_t size) {
+    for (size_t i = 0; i < size; ++i) {
+        uint8_t byte = data[i];
+        out << (nibble2hex[0x0F & (byte >> 4)]);
+        out << (nibble2hex[0x0F & byte]);
+        switch (i & 0xf) {
+            case 0xf:
+                out << "\n";
+                break;
+            case 7:
+                out << "  ";
+                break;
+            default:
+                out << " ";
+                break;
+        }
+    }
+    return out;
+}
+
+}  // namespace
+#endif
+
+TEST(MsgFormattingTest, FeatureTest) {
+    uint8_t buffer[0x1000];
+
+    WriteStream out(buffer);
+    out = unalign(out);
+    out += 4;
+    auto begin = out.pos();
+    out = write(
+        PromptUserConfirmationMsg(), out, hidl_string("Do you?"),
+        hidl_vec<uint8_t>{0x01, 0x02, 0x03}, hidl_string("en"),
+        hidl_vec<UIOption>{UIOption::AccessibilityInverted, UIOption::AccessibilityMagnified});
+
+    ReadStream in(buffer);
+    in = unalign(in);
+    in += 4;
+    hidl_string prompt;
+    hidl_vec<uint8_t> extra;
+    hidl_string locale;
+    hidl_vec<UIOption> uiOpts;
+    bool command_matches;
+    std::tie(in, command_matches, prompt, extra, locale, uiOpts) =
+        read(PromptUserConfirmationMsg(), in);
+    ASSERT_TRUE(in);
+    ASSERT_TRUE(command_matches);
+    ASSERT_EQ(hidl_string("Do you?"), prompt);
+    ASSERT_EQ((hidl_vec<uint8_t>{0x01, 0x02, 0x03}), extra);
+    ASSERT_EQ(hidl_string("en"), locale);
+    ASSERT_EQ(
+        (hidl_vec<UIOption>{UIOption::AccessibilityInverted, UIOption::AccessibilityMagnified}),
+        uiOpts);
+
+#ifdef DEBUG_MSG_FORMATTING
+    hexdump(std::cout, buffer, 100) << std::endl;
+#endif
+
+    // The following assertions check that the hidl_[vec|string] types are in fact read in place,
+    // and no copying occurs. Copying results in heap allocation which we intend to avoid.
+    ASSERT_EQ(8, const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(prompt.c_str())) - begin);
+    ASSERT_EQ(20, extra.data() - begin);
+    ASSERT_EQ(27, const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(locale.c_str())) - begin);
+    ASSERT_EQ(40, reinterpret_cast<uint8_t*>(uiOpts.data()) - begin);
+}
+
+TEST(MsgFormattingTest, HardwareAuthTokenTest) {
+    uint8_t buffer[0x1000];
+
+    HardwareAuthToken expected, actual;
+    expected.authenticatorId = 0xa1a3a4a5a6a7a8;
+    expected.authenticatorType = HardwareAuthenticatorType::NONE;
+    expected.challenge = 0xb1b2b3b4b5b6b7b8;
+    expected.userId = 0x1122334455667788;
+    expected.timestamp = 0xf1f2f3f4f5f6f7f8;
+    expected.mac =
+        hidl_vec<uint8_t>{1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16,
+                          17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
+
+    WriteStream out(buffer);
+    out = write(Message<HardwareAuthToken>(), out, expected);
+    ReadStream in(buffer);
+    std::tie(in, actual) = read(Message<HardwareAuthToken>(), in);
+    ASSERT_EQ(expected, actual);
+}
diff --git a/contexthub/1.0/default/Contexthub.cpp b/contexthub/1.0/default/Contexthub.cpp
index 3626a09..5f83a22 100644
--- a/contexthub/1.0/default/Contexthub.cpp
+++ b/contexthub/1.0/default/Contexthub.cpp
@@ -155,6 +155,12 @@
         .message = static_cast<const uint8_t *>(msg.msg.data()),
     };
 
+    // Use a dummy to prevent send_message with empty message from failing prematurely
+    static uint8_t dummy;
+    if (txMsg.message_len == 0 && txMsg.message == nullptr) {
+        txMsg.message = &dummy;
+    }
+
     ALOGI("Sending msg of type %" PRIu32 ", size %" PRIu32 " to app 0x%" PRIx64,
           txMsg.message_type,
           txMsg.message_len,
@@ -275,11 +281,11 @@
                 result = TransactionResult::FAILURE;
             }
 
+            mIsTransactionPending = false;
             if (cb != nullptr) {
                 cb->handleTxnResult(mTransactionId, result);
             }
             retVal = 0;
-            mIsTransactionPending = false;
             break;
         }
 
@@ -377,6 +383,7 @@
 
         msg.appName = rxMsg->app_name.id;
         msg.msgType = rxMsg->message_type;
+        msg.hostEndPoint = static_cast<uint16_t>(HostEndPoint::BROADCAST);
         msg.msg = std::vector<uint8_t>(static_cast<const uint8_t *>(rxMsg->message),
                                        static_cast<const uint8_t *>(rxMsg->message) +
                                        rxMsg->message_len);
diff --git a/contexthub/1.0/default/OWNERS b/contexthub/1.0/default/OWNERS
new file mode 100644
index 0000000..49a3204
--- /dev/null
+++ b/contexthub/1.0/default/OWNERS
@@ -0,0 +1,2 @@
+ashutoshj@google.com
+bduddie@google.com
diff --git a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
index 5677ec2..a8c9487 100644
--- a/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
+++ b/contexthub/1.0/default/android.hardware.contexthub@1.0-service.rc
@@ -1,4 +1,4 @@
-service contexthub-hal-1-0 /vendor/bin/hw/android.hardware.contexthub@1.0-service
+service vendor.contexthub-hal-1-0 /vendor/bin/hw/android.hardware.contexthub@1.0-service
     class hal
     user system
     group system
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
new file mode 100644
index 0000000..ad036b4
--- /dev/null
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -0,0 +1,7 @@
+#Context Hub team
+ashutoshj@google.com
+bduddie@google.com
+
+#VTS team
+yim@google.com
+trong@google.com
diff --git a/current.txt b/current.txt
index bdd1fbf..a5ab307 100644
--- a/current.txt
+++ b/current.txt
@@ -221,7 +221,9 @@
 b056e1defab4071584214584057d0bc73a613081bf1152590549649d4582c13c android.hardware.wifi@1.1::IWifiChip
 
 # ABI preserving changes to HALs during Android O MR1 (Final Set)
+09342041e17c429fce0034b9096d17849122111436a5f0053e7e59500e1cb89c android.hardware.media.omx@1.0::IOmxStore
 2d833aeed0cd1d59437aca210be590a953cf32bcb6683cd63d089762a643fb49 android.hardware.radio@1.0::IRadioResponse
+0a159f81359cd4f71bbe00972ee8403ea79351fb7c0cd48be72ebb3e424dbaef android.hardware.radio@1.0::types
 05aa3de6130a9788fdb6f4d3cc57c3ea90f067e77a5e09d6a772ec7f6bca33d2 android.hardware.radio@1.1::IRadioResponse
 
 # HALs released in Android O MR1 (Final Set)
@@ -239,8 +241,6 @@
 86ba9c03978b79a742e990420bc5ced0673d25a939f82572996bef92621e2014 android.hardware.cas@1.0::IMediaCasService
 503da837d1a67cbdb7c08a033e927e5430ae1b159d98bf72c6336b4dcc5e76f5 android.hardware.cas.native@1.0::types
 619600109232ed64b827c8a11beed8070b1827ae464547d7aa146cf0473b4bca android.hardware.cas.native@1.0::IDescrambler
-0a159f81359cd4f71bbe00972ee8403ea79351fb7c0cd48be72ebb3e424dbaef android.hardware.radio@1.0::types
-09342041e17c429fce0034b9096d17849122111436a5f0053e7e59500e1cb89c android.hardware.media.omx@1.0::IOmxStore
 246a56d37d57a47224562c9d077b4a2886ce6242b9311bd98a17325944c280d7 android.hardware.neuralnetworks@1.0::types
 93eb3757ceaf21590fa4cd1d4a7dfe3b3794af5396100a6d25630879352abce9 android.hardware.neuralnetworks@1.0::IDevice
 f66f9a38541bf92001d3adcce678cd7e3da2262124befb460b1c9aea9492813b android.hardware.neuralnetworks@1.0::IExecutionCallback
@@ -248,3 +248,11 @@
 73e03573494ba96f0e711ab7f1956c5b2d54c3da690cd7ecf4d6d0f287447730 android.hardware.neuralnetworks@1.0::IPreparedModelCallback
 f4945e397b5dea41bb64518dfde59be71245d8a125fd1e0acffeb57ac7b08fed android.hardware.thermal@1.1::IThermal
 c8bc853546dd55584611def2a9fa1d99f657e3366c976d2f60fe6b8aa6d2cb87 android.hardware.thermal@1.1::IThermalCallback
+
+# ABI preserving changes to HALs during Android P
+cf72ff5a52bfa4d08e9e1000cf3ab5952a2d280c7f13cdad5ab7905c08050766 android.hardware.camera.metadata@3.2::types
+6fa9804a17a8bb7923a56bd10493a5483c20007e4c9026fd04287bee7c945a8c android.hardware.gnss@1.0::IGnssCallback
+fb92e2b40f8e9d494e8fd3b4ac18499a3216342e7cff160714c3bbf3660b6e79 android.hardware.gnss@1.0::IGnssConfiguration
+251594ea9b27447bfa005ebd806e58fb0ae4aad84a69938129c9800ec0c64eda android.hardware.gnss@1.0::IGnssMeasurementCallback
+4e7169919d24fbe5573e5bcd683d0bd7abf553a4e6c34c41f9dfc1e12050db07 android.hardware.gnss@1.0::IGnssNavigationMessageCallback
+b280c4704dfcc548a9bf127b59b7c3578f460c50cce70a06b66fe0df8b27cff0 android.hardware.wifi@1.0::types
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index fd75dbd..f9c868d 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -99,8 +99,8 @@
         legacyPattern.mEncryptBlocks = pattern.encryptBlocks;
         legacyPattern.mSkipBlocks = pattern.skipBlocks;
 
-        android::CryptoPlugin::SubSample *legacySubSamples =
-            new android::CryptoPlugin::SubSample[subSamples.size()];
+        std::unique_ptr<android::CryptoPlugin::SubSample[]> legacySubSamples =
+                std::make_unique<android::CryptoPlugin::SubSample[]>(subSamples.size());
 
         for (size_t i = 0; i < subSamples.size(); i++) {
             legacySubSamples[i].mNumBytesOfClearData
@@ -145,11 +145,9 @@
             destPtr = static_cast<void *>(handle);
         }
         ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(),
-                legacyMode, legacyPattern, srcPtr, legacySubSamples,
+                legacyMode, legacyPattern, srcPtr, legacySubSamples.get(),
                 subSamples.size(), destPtr, &detailMessage);
 
-        delete[] legacySubSamples;
-
         uint32_t status;
         uint32_t bytesWritten;
 
diff --git a/drm/1.0/default/DrmPlugin.cpp b/drm/1.0/default/DrmPlugin.cpp
index 1695ef7..809f694 100644
--- a/drm/1.0/default/DrmPlugin.cpp
+++ b/drm/1.0/default/DrmPlugin.cpp
@@ -93,6 +93,7 @@
                 requestType = KeyRequestType::RELEASE;
                 break;
             case android::DrmPlugin::kKeyRequestType_Unknown:
+            default:
                 requestType = KeyRequestType::UNKNOWN;
                 break;
             }
diff --git a/drm/1.0/default/android.hardware.drm@1.0-service.rc b/drm/1.0/default/android.hardware.drm@1.0-service.rc
index e7beca3..a3457b5 100644
--- a/drm/1.0/default/android.hardware.drm@1.0-service.rc
+++ b/drm/1.0/default/android.hardware.drm@1.0-service.rc
@@ -1,4 +1,4 @@
-service drm-hal-1-0 /vendor/bin/hw/android.hardware.drm@1.0-service
+service vendor.drm-hal-1-0 /vendor/bin/hw/android.hardware.drm@1.0-service
     class hal
     user media
     group mediadrm drmrpc
diff --git a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
index a110eb1..4a1892b 100644
--- a/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_clearkey_test.cpp
@@ -89,10 +89,6 @@
     0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
     0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
 
-static const uint32_t k256SubSampleByteCount = 256;
-static const uint32_t k512SubSampleClearBytes = 512;
-static const uint32_t k512SubSampleEncryptedBytes = 512;
-
 class DrmHalClearkeyFactoryTest : public ::testing::VtsHalHidlTargetTestBase {
    public:
     virtual void SetUp() override {
@@ -349,8 +345,7 @@
  * Helper method to close a session
  */
 void DrmHalClearkeyPluginTest::closeSession(const SessionId& sessionId) {
-    auto result = drmPlugin->closeSession(sessionId);
-    EXPECT_EQ(Status::OK, result);
+    EXPECT_TRUE(drmPlugin->closeSession(sessionId).isOk());
 }
 
 /**
@@ -793,7 +788,7 @@
  */
 TEST_F(DrmHalClearkeyPluginTest, GenericEncryptNotSupported) {
     SessionId session = openSession();
-    ;
+
     hidl_vec<uint8_t> keyId = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
     hidl_vec<uint8_t> input = {1, 2, 3, 4, 5};
     hidl_vec<uint8_t> iv = std::vector<uint8_t>(AES_BLOCK_SIZE, 0);
@@ -822,7 +817,7 @@
 
 TEST_F(DrmHalClearkeyPluginTest, GenericSignNotSupported) {
     SessionId session = openSession();
-    ;
+
     hidl_vec<uint8_t> keyId = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
     hidl_vec<uint8_t> message = {1, 2, 3, 4, 5};
     auto res = drmPlugin->sign(session, keyId, message,
@@ -836,7 +831,7 @@
 
 TEST_F(DrmHalClearkeyPluginTest, GenericVerifyNotSupported) {
     SessionId session = openSession();
-    ;
+
     hidl_vec<uint8_t> keyId = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
     hidl_vec<uint8_t> message = {1, 2, 3, 4, 5};
     hidl_vec<uint8_t> signature = {0, 0, 0, 0, 0, 0, 0, 0,
@@ -926,8 +921,7 @@
  */
 TEST_F(DrmHalClearkeyPluginTest, SetMediaDrmSession) {
     auto sessionId = openSession();
-    Status status = cryptoPlugin->setMediaDrmSession(sessionId);
-    EXPECT_EQ(Status::OK, status);
+    EXPECT_TRUE(cryptoPlugin->setMediaDrmSession(sessionId).isOk());
     closeSession(sessionId);
 }
 
@@ -948,8 +942,7 @@
  */
 TEST_F(DrmHalClearkeyPluginTest, SetMediaDrmSessionEmptySession) {
     SessionId sessionId;
-    Status status = cryptoPlugin->setMediaDrmSession(sessionId);
-    EXPECT_EQ(Status::OK, status);
+    EXPECT_TRUE(cryptoPlugin->setMediaDrmSession(sessionId).isOk());
 }
 
 /**
@@ -1131,18 +1124,17 @@
 TEST_F(DrmHalClearkeyDecryptTest, ClearSegmentTest) {
     vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
     const Pattern noPattern = {0, 0};
+    const uint32_t kByteCount = 256;
     const vector<SubSample> subSamples = {
-        {.numBytesOfClearData = k256SubSampleByteCount,
+        {.numBytesOfClearData = kByteCount,
          .numBytesOfEncryptedData = 0}};
     auto sessionId = openSession();
     loadKeys(sessionId);
-
-    Status status = cryptoPlugin->setMediaDrmSession(sessionId);
-    EXPECT_EQ(Status::OK, status);
+    EXPECT_TRUE(cryptoPlugin->setMediaDrmSession(sessionId).isOk());
 
     uint32_t byteCount = decrypt(Mode::UNENCRYPTED, &iv[0], subSamples,
             noPattern, Status::OK);
-    EXPECT_EQ(k256SubSampleByteCount, byteCount);
+    EXPECT_EQ(kByteCount, byteCount);
 
     closeSession(sessionId);
 }
@@ -1154,18 +1146,18 @@
 TEST_F(DrmHalClearkeyDecryptTest, EncryptedAesCtrSegmentTest) {
     vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
     const Pattern noPattern = {0, 0};
+    const uint32_t kClearBytes = 512;
+    const uint32_t kEncryptedBytes = 512;
     const vector<SubSample> subSamples = {
-        {.numBytesOfClearData = k512SubSampleClearBytes,
-         .numBytesOfEncryptedData = k512SubSampleEncryptedBytes}};
+        {.numBytesOfClearData = kClearBytes,
+         .numBytesOfEncryptedData = kEncryptedBytes}};
     auto sessionId = openSession();
     loadKeys(sessionId);
-
-    Status status = cryptoPlugin->setMediaDrmSession(sessionId);
-    EXPECT_EQ(Status::OK, status);
+    EXPECT_TRUE(cryptoPlugin->setMediaDrmSession(sessionId).isOk());
 
     uint32_t byteCount = decrypt(Mode::AES_CTR, &iv[0], subSamples,
             noPattern, Status::OK);
-    EXPECT_EQ(k512SubSampleClearBytes + k512SubSampleEncryptedBytes, byteCount);
+    EXPECT_EQ(kClearBytes + kEncryptedBytes, byteCount);
 
     closeSession(sessionId);
 }
@@ -1177,12 +1169,10 @@
     vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
     const Pattern noPattern = {0, 0};
     const vector<SubSample> subSamples = {
-        {.numBytesOfClearData = k256SubSampleByteCount,
-         .numBytesOfEncryptedData = k256SubSampleByteCount}};
+        {.numBytesOfClearData = 256,
+         .numBytesOfEncryptedData = 256}};
     auto sessionId = openSession();
-
-    Status status = cryptoPlugin->setMediaDrmSession(sessionId);
-    EXPECT_EQ(Status::OK, status);
+    EXPECT_TRUE(cryptoPlugin->setMediaDrmSession(sessionId).isOk());
 
     uint32_t byteCount = decrypt(Mode::AES_CTR, &iv[0], subSamples,
             noPattern, Status::ERROR_DRM_NO_LICENSE);
@@ -1207,9 +1197,9 @@
             EXPECT_EQ(Status::OK, status);
             EXPECT_EQ(0u, myKeySetId.size());
         });
-    ASSERT_OK(res);
+    EXPECT_OK(res);
 
-    ASSERT_TRUE(cryptoPlugin->setMediaDrmSession(sessionId).isOk());
+    EXPECT_TRUE(cryptoPlugin->setMediaDrmSession(sessionId).isOk());
 
     uint32_t byteCount = decrypt(Mode::AES_CTR, &iv[0], subSamples,
             noPattern, Status::ERROR_DRM_NO_LICENSE);
@@ -1224,9 +1214,11 @@
 TEST_F(DrmHalClearkeyDecryptTest, DecryptWithEmptyKey) {
     vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
     const Pattern noPattern = {0, 0};
+    const uint32_t kClearBytes = 512;
+    const uint32_t kEncryptedBytes = 512;
     const vector<SubSample> subSamples = {
-        {.numBytesOfClearData = k512SubSampleClearBytes,
-         .numBytesOfEncryptedData = k512SubSampleEncryptedBytes}};
+        {.numBytesOfClearData = kClearBytes,
+         .numBytesOfEncryptedData = kEncryptedBytes}};
 
     // base 64 encoded JSON response string, must not contain padding character '='
     const hidl_string emptyKeyResponse =
@@ -1259,9 +1251,11 @@
 TEST_F(DrmHalClearkeyDecryptTest, DecryptWithKeyTooLong) {
     vector<uint8_t> iv(AES_BLOCK_SIZE, 0);
     const Pattern noPattern = {0, 0};
+    const uint32_t kClearBytes = 512;
+    const uint32_t kEncryptedBytes = 512;
     const vector<SubSample> subSamples = {
-        {.numBytesOfClearData = k512SubSampleClearBytes,
-         .numBytesOfEncryptedData = k512SubSampleEncryptedBytes}};
+        {.numBytesOfClearData = kClearBytes,
+         .numBytesOfEncryptedData = kEncryptedBytes}};
 
     // base 64 encoded JSON response string, must not contain padding character '='
     const hidl_string keyTooLongResponse =
diff --git a/drm/1.1/Android.bp b/drm/1.1/Android.bp
new file mode 100644
index 0000000..ed8196e
--- /dev/null
+++ b/drm/1.1/Android.bp
@@ -0,0 +1,26 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.drm@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ICryptoFactory.hal",
+        "IDrmFactory.hal",
+        "IDrmPlugin.hal",
+    ],
+    interfaces: [
+        "android.hardware.drm@1.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "HdcpLevel",
+        "KeyRequestType",
+        "SecurityLevel",
+    ],
+    gen_java: false,
+}
+
diff --git a/drm/1.1/ICryptoFactory.hal b/drm/1.1/ICryptoFactory.hal
new file mode 100644
index 0000000..1f8caa5
--- /dev/null
+++ b/drm/1.1/ICryptoFactory.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.drm@1.1;
+
+import @1.0::ICryptoFactory;
+import @1.0::ICryptoPlugin;
+
+/**
+ * ICryptoFactory is the main entry point for interacting with a vendor's
+ * crypto HAL to create crypto plugins. Crypto plugins create crypto sessions
+ * which are used by a codec to decrypt protected video content.
+ *
+ * The 1.1 factory must always create 1.0 ICryptoPlugin interfaces, which are
+ * returned via the 1.0 createPlugin method.
+ *
+ * The ICryptoFactory hal is required because all top-level interfaces
+ * have to be updated in a minor uprev.
+ */
+interface ICryptoFactory extends @1.0::ICryptoFactory {
+};
diff --git a/drm/1.1/IDrmFactory.hal b/drm/1.1/IDrmFactory.hal
new file mode 100644
index 0000000..b6d6bfb
--- /dev/null
+++ b/drm/1.1/IDrmFactory.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.drm@1.1;
+
+import @1.0::IDrmFactory;
+import @1.0::IDrmPlugin;
+
+/**
+ * IDrmFactory is the main entry point for interacting with a vendor's
+ * drm HAL to create drm plugin instances. A drm plugin instance
+ * creates drm sessions which are used to obtain keys for a crypto
+ * session so it can decrypt protected video content.
+ *
+ * The 1.1 factory must always create 1.1 IDrmPlugin interfaces, which are
+ * returned via the 1.0 createPlugin method.
+ *
+ * To use 1.1 features the caller must cast the returned interface to a
+ * 1.1 HAL, using V1_1::IDrmPlugin::castFrom().
+ */
+
+interface IDrmFactory extends @1.0::IDrmFactory {
+};
diff --git a/drm/1.1/IDrmPlugin.hal b/drm/1.1/IDrmPlugin.hal
new file mode 100644
index 0000000..7dd397a
--- /dev/null
+++ b/drm/1.1/IDrmPlugin.hal
@@ -0,0 +1,233 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.drm@1.1;
+
+import @1.0::IDrmPlugin;
+import @1.0::IDrmPluginListener;
+import @1.0::KeyedVector;
+import @1.0::KeyType;
+import @1.0::Status;
+import @1.1::DrmMetricGroup;
+import @1.1::HdcpLevel;
+import @1.1::KeyRequestType;
+import @1.0::SecureStopId;
+import @1.1::SecureStopRelease;
+import @1.1::SecurityLevel;
+
+/**
+ * IDrmPlugin is used to interact with a specific drm plugin that was created by
+ * IDrm::createPlugin. A drm plugin provides methods for obtaining drm keys that
+ * may be used by a codec to decrypt protected video content.
+ */
+interface IDrmPlugin extends @1.0::IDrmPlugin {
+    /**
+     * A key request/response exchange occurs between the app and a License
+     * Server to obtain the keys required to decrypt the content.
+     * getKeyRequest_1_1() is used to obtain an opaque key request blob that is
+     * delivered to the license server.
+     *
+     * getKeyRequest_1_1() only differs from getKeyRequest() in that additional
+     * values are returned in 1.1::KeyRequestType as compared to
+     * 1.0::KeyRequestType
+     *
+     * @param scope may be a sessionId or a keySetId, depending on the
+     *        specified keyType. When the keyType is OFFLINE or STREAMING,
+     *        scope should be set to the sessionId the keys will be provided
+     *        to. When the keyType is RELEASE, scope should be set to the
+     *        keySetId of the keys being released.
+     * @param initData container-specific data, its meaning is interpreted
+     *        based on the mime type provided in the mimeType parameter.
+     *        It could contain, for example, the content ID, key ID or
+     *        other data obtained from the content metadata that is
+     *        required to generate the key request. initData may be empty
+     *        when keyType is RELEASE.
+     * @param mimeType identifies the mime type of the content
+     * @param keyType specifies if the keys are to be used for streaming,
+     *        offline or a release
+     * @param optionalParameters included in the key request message to
+     *        allow a client application to provide additional message
+     *        parameters to the server.
+     * @return status the status of the call. The status must be OK or one of
+     *         the following errors: ERROR_DRM_SESSION_NOT_OPENED if the
+     *         session is not opened, ERROR_DRM_NOT_PROVISIONED if the device
+     *         requires provisioning before it can generate a key request,
+     *         ERROR_DRM_CANNOT_HANDLE if getKeyRequest is not supported
+     *         at the time of the call, BAD_VALUE if any parameters are
+     *         invalid or ERROR_DRM_INVALID_STATE if the HAL is in a
+     *         state where a key request cannot be generated.
+     * @return request if successful, the opaque key request blob is returned
+     * @return requestType indicates type information about the returned
+     *         request. The type may be one of INITIAL, RENEWAL, RELEASE,
+     *         NONE or UPDATE. An INITIAL request is the first key request
+     *         for a license. RENEWAL is a subsequent key request used to
+     *         refresh the keys in a license. RELEASE corresponds to a
+     *         keyType of RELEASE, which indicates keys are being released.
+     *         NONE indicates that no request is needed because the keys are
+     *         already loaded. UPDATE indicates that the keys need to be
+     *         refetched after the initial license request.
+     * @return defaultUrl the URL that the request may be sent to, if
+     *         provided by the drm HAL. The app may choose to override this URL.
+     */
+    getKeyRequest_1_1(vec<uint8_t> scope, vec<uint8_t> initData,
+            string mimeType, KeyType keyType, KeyedVector optionalParameters)
+        generates (Status status, vec<uint8_t> request,
+                KeyRequestType requestType, string defaultUrl);
+
+    /**
+     * Return the currently negotiated and max supported HDCP levels.
+     *
+     * The current level is based on the display(s) the device is connected to.
+     * If multiple HDCP-capable displays are simultaneously connected to
+     * separate interfaces, this method returns the lowest negotiated HDCP level
+     * of all interfaces.
+     *
+     * The maximum HDCP level is the highest level that can potentially be
+     * negotiated. It is a constant for any device, i.e. it does not depend on
+     * downstream receiving devices that could be connected. For example, if
+     * the device has HDCP 1.x keys and is capable of negotiating HDCP 1.x, but
+     * does not have HDCP 2.x keys, then the maximum HDCP capability would be
+     * reported as 1.x. If multiple HDCP-capable interfaces are present, it
+     * indicates the highest of the maximum HDCP levels of all interfaces.
+     *
+     * This method should only be used for informational purposes, not for
+     * enforcing compliance with HDCP requirements. Trusted enforcement of HDCP
+     * policies must be handled by the DRM system.
+     *
+     * @return status the status of the call. The status must be OK or
+     *         ERROR_DRM_INVALID_STATE if the HAL is in a state where the HDCP
+     *         level cannot be queried.
+     * @return connectedLevel the lowest HDCP level for any connected
+     *         displays
+     * @return maxLevel the highest HDCP level that can be supported
+     *         by the device
+     */
+    getHdcpLevels() generates (Status status, HdcpLevel connectedLevel,
+            HdcpLevel maxLevel);
+
+    /**
+     * Return the current number of open sessions and the maximum number of
+     * sessions that may be opened simultaneosly among all DRM instances for the
+     * active DRM scheme.
+     *
+     * @return status the status of the call. The status must be OK or
+     *         ERROR_DRM_INVALID_STATE if the HAL is in a state where number of
+     *         sessions cannot be queried.
+     * @return currentSessions the number of currently opened sessions
+     * @return maxSessions the maximum number of sessions that the device
+     *         can support
+     */
+    getNumberOfSessions() generates (Status status, uint32_t currentSessions,
+             uint32_t maxSessions);
+
+    /**
+     * Return the current security level of a session. A session has an initial
+     * security level determined by the robustness of the DRM system's
+     * implementation on the device.
+     *
+     * @param sessionId the session id the call applies to
+     * @return status the status of the call. The status must be OK or one of
+     *         the following errors: ERROR_DRM_SESSION_NOT_OPENED if the
+     *         session is not opened, BAD_VALUE if the sessionId is invalid or
+     *         ERROR_DRM_INVALID_STATE if the HAL is in a state where the
+     *         security level cannot be queried.
+     * @return level the current security level for the session
+     */
+    getSecurityLevel(vec<uint8_t> sessionId) generates(Status status,
+            SecurityLevel level);
+
+    /**
+     * Set the security level of a session. This can be useful if specific
+     * attributes of a lower security level are needed by an application, such
+     * as image manipulation or compositing which requires non-secure decoded
+     * frames. Reducing the security level may limit decryption to lower content
+     * resolutions, depending on the license policy.
+     *
+     * @param sessionId the session id the call applies to
+     * @param level the requested security level
+     * @return status the status of the call. The status must be OK or one of
+     *         the following errors: ERROR_DRM_SESSION_NOT_OPENED if the session
+     *         is not opened, BAD_VALUE if the sessionId or security level is
+     *         invalid or ERROR_DRM_INVALID_STATE if the HAL is in a state where
+     *         the security level cannot be set.
+     */
+    setSecurityLevel(vec<uint8_t> sessionId, SecurityLevel level)
+            generates(Status status);
+
+    /**
+     * Returns the plugin-specific metrics. Multiple metric groups may be
+     * returned in one call to getMetrics(). The scope and definition of the
+     * metrics is defined by the plugin.
+     *
+     * @return status the status of the call. The status must be OK or
+     *         ERROR_DRM_INVALID_STATE if the metrics are not available to be
+     *         returned.
+     * @return metric_groups the collection of metric groups provided by the
+     *         plugin.
+     */
+    getMetrics() generates (Status status, vec<DrmMetricGroup> metric_groups);
+
+    /**
+     * Get the IDs of all secure stops on the device
+     *
+     * @return status the status of the call. The status must be OK or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop
+     * IDs cannot be returned.
+     * @return secureStopIds a list of the IDs
+     */
+    getSecureStopIds() generates
+        (Status status, vec<SecureStopId> secureStopIds);
+
+    /**
+     * Release secure stops given a release message from the key server
+     *
+     * @param ssRelease the secure stop release message identifying one or more
+     * secure stops to release. ssRelease is opaque, it is passed directly from
+     * a DRM license server through the app and media framework to the vendor
+     * HAL module. The format and content of ssRelease must be defined by the
+     * DRM scheme being implemented according to this HAL. The DRM scheme
+     * can be identified by its UUID which can be queried using
+     * IDrmFactory::isCryptoSchemeSupported.
+     *
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if ssRelease is invalid or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop
+     * cannot be released.
+     */
+    releaseSecureStops(SecureStopRelease ssRelease) generates (Status status);
+
+    /**
+     * Remove a secure stop given its secure stop ID, without requiring
+     * a secure stop release response message from the key server.
+     *
+     * @param secureStopId the ID of the secure stop to release.
+     *
+     * @return status the status of the call. The status must be OK or one of
+     * the following errors: BAD_VALUE if the secureStopId is invalid or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure stop
+     * cannot be released.
+     */
+    removeSecureStop(SecureStopId secureStopId) generates (Status status);
+
+    /**
+     * Remove all secure stops on the device without requiring a secure
+     * stop release response message from the key server.
+     *
+     * @return status the status of the call. The status must be OK or
+     * ERROR_DRM_INVALID_STATE if the HAL is in a state where the secure
+     * stops cannot be removed.
+     */
+    removeAllSecureStops() generates (Status status);
+};
diff --git a/drm/1.1/types.hal b/drm/1.1/types.hal
new file mode 100644
index 0000000..015f1b7
--- /dev/null
+++ b/drm/1.1/types.hal
@@ -0,0 +1,219 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.drm@1.1;
+
+import @1.0::KeyRequestType;
+
+/**
+ * This message contains plugin-specific metrics made available to the client.
+ * The message is used for making vendor-specific metrics available to an
+ * application. The framework is not consuming any of the information.
+ *
+ * Metrics are grouped in instances of DrmMetricGroup. Each group contains
+ * multiple instances of Metric.
+ *
+ * Example:
+ *
+ * Capture the timing information of a buffer copy event, "buf_copy", broken
+ * out by the "size" of the buffer.
+ *
+ * DrmMetricGroup {
+ *   metrics[0] {
+ *     name: "buf_copy"
+ *     attributes[0] {
+ *       name: "size"
+ *       type: INT64_TYPE
+ *       int64Value: 1024
+ *     }
+ *     values[0] {
+ *       componentName: "operation_count"
+ *       type: INT64_TYPE
+ *       int64Value: 75
+ *     }
+ *     values[1] {
+ *       component_name: "average_time_seconds"
+ *       type: DOUBLE_TYPE
+ *       doubleValue: 0.00000042
+ *     }
+ *   }
+ * }
+ */
+struct DrmMetricGroup {
+    /**
+     * Used to discriminate the type of value being stored in the structs
+     * below.
+     */
+    enum ValueType : uint8_t {
+        INT64_TYPE,
+        DOUBLE_TYPE,
+        STRING_TYPE,
+    };
+
+    /**
+     * A detail about the metric being captured. The fields of an Attribute
+     * are opaque to the framework.
+     */
+    struct Attribute {
+        string name;
+        /**
+         * The type field indicates which of the following values is used.
+         */
+        ValueType type;
+        int64_t int64Value;
+        double doubleValue;
+        string stringValue;
+    };
+
+    /**
+     * A value of the metric. A metric may have multiple values. The
+     * component name may be left empty if there is only supposed to be
+     * one value for the given metric. The fields of the Value are
+     * opaque to the framework.
+     */
+    struct Value {
+        string componentName;
+        /**
+         * The type field indicates which of the following values is used.
+         */
+        ValueType type;
+        int64_t int64Value;
+        double doubleValue;
+        string stringValue;
+    };
+
+    /**
+     * The metric being captured. A metric must have a name and at least one
+     * value. A metric may have 0 or more attributes. The fields of a Metric
+     * are opaque to the framework.
+     */
+    struct Metric {
+        string name;
+        vec<Attribute> attributes;
+        // A Metric may have one or more values. Multiple values are useful
+        // for capturing different aspects of the same metric. E.g. capture
+        // the min, max, average, count, and stdev of a particular metric.
+        vec<Value> values;
+    };
+
+    /**
+     * The list of metrics to be captured.
+     */
+    vec<Metric> metrics;
+};
+
+/**
+ * HDCP specifications are defined by Digital Content Protection LLC (DCP).
+ *   "HDCP Specification Rev. 2.2 Interface Independent Adaptation"
+ *   "HDCP 2.2 on HDMI Specification"
+ */
+enum HdcpLevel : uint32_t {
+    /**
+     * Unable to determine the HDCP level
+     */
+    HDCP_UNKNOWN,
+
+    /**
+     * No HDCP, output is unprotected
+     */
+    HDCP_NONE,
+
+    /**
+     * HDCP version 1.0
+     */
+    HDCP_V1,
+
+    /**
+     * HDCP version 2.0 Type 1.
+     */
+    HDCP_V2,
+
+    /**
+     * HDCP version 2.1 Type 1.
+     */
+    HDCP_V2_1,
+
+    /**
+     *  HDCP version 2.2 Type 1.
+     */
+    HDCP_V2_2,
+
+    /**
+     * No digital output, implicitly secure
+     */
+    HDCP_NO_OUTPUT
+};
+
+/**
+ * KeyRequestTypes (in addition to those from 1.0) which allow an app
+ * to determine the type of a key request returned from getKeyRequest.
+ */
+enum KeyRequestType : @1.0::KeyRequestType {
+    /**
+     * Keys are already loaded. No key request is needed.
+     */
+    NONE,
+
+    /**
+     * Keys have previously been loaded. An additional (non-renewal) license
+     * request is needed.
+     */
+    UPDATE,
+};
+
+enum SecurityLevel : uint32_t {
+    /**
+     * Unable to determine the security level
+     */
+    UNKNOWN,
+
+    /**
+     * Software-based whitebox crypto
+     */
+    SW_SECURE_CRYPTO,
+
+    /**
+     * Software-based whitebox crypto and an obfuscated decoder
+     */
+    SW_SECURE_DECODE,
+
+    /**
+     * DRM key management and crypto operations are performed within a
+     * hardware backed trusted execution environment
+     */
+    HW_SECURE_CRYPTO,
+
+    /**
+     * DRM key management, crypto operations and decoding of content
+     * are performed within a hardware backed trusted execution environment
+     */
+    HW_SECURE_DECODE,
+
+    /**
+     * DRM key management, crypto operations, decoding of content and all
+     * handling of the media (compressed and uncompressed) is handled within
+     * a hardware backed trusted execution environment.
+     */
+    HW_SECURE_ALL,
+};
+
+/**
+ * Encapsulates a secure stop release opaque object
+ */
+struct SecureStopRelease {
+    vec<uint8_t> opaqueData;
+};
+
diff --git a/drm/1.1/vts/functional/Android.bp b/drm/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..782f283
--- /dev/null
+++ b/drm/1.1/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalDrmV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "drm_hal_clearkey_test.cpp"
+    ],
+    static_libs: [
+        "android.hardware.drm@1.0",
+        "android.hardware.drm@1.1",
+        "android.hardware.drm@1.0-helper",
+        "android.hidl.allocator@1.0",
+        "android.hidl.memory@1.0",
+        "libhidlmemory",
+        "libnativehelper",
+        "libssl",
+        "libcrypto",
+    ],
+}
diff --git a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
new file mode 100644
index 0000000..62cc8b6
--- /dev/null
+++ b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "drm_hal_clearkey_test@1.1"
+
+#include <android/hardware/drm/1.1/ICryptoFactory.h>
+#include <android/hardware/drm/1.0/ICryptoPlugin.h>
+#include <android/hardware/drm/1.1/IDrmFactory.h>
+#include <android/hardware/drm/1.0/IDrmPlugin.h>
+#include <android/hardware/drm/1.1/IDrmPlugin.h>
+#include <android/hardware/drm/1.0/types.h>
+#include <android/hardware/drm/1.1/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <hidlmemory/mapping.h>
+#include <log/log.h>
+#include <memory>
+#include <openssl/aes.h>
+#include <random>
+
+#include "VtsHalHidlTargetTestBase.h"
+#include "VtsHalHidlTargetTestEnvBase.h"
+
+namespace drm = ::android::hardware::drm;
+using ::android::hardware::drm::V1_0::BufferType;
+using ::android::hardware::drm::V1_0::DestinationBuffer;
+using ::android::hardware::drm::V1_0::ICryptoPlugin;
+using ::android::hardware::drm::V1_0::KeyedVector;
+using ::android::hardware::drm::V1_0::KeyValue;
+using ::android::hardware::drm::V1_0::KeyRequestType;
+using ::android::hardware::drm::V1_0::KeyType;
+using ::android::hardware::drm::V1_0::Mode;
+using ::android::hardware::drm::V1_0::Pattern;
+using ::android::hardware::drm::V1_0::SecureStop;
+using ::android::hardware::drm::V1_0::SecureStopId;
+using ::android::hardware::drm::V1_0::SessionId;
+using ::android::hardware::drm::V1_0::SharedBuffer;
+using ::android::hardware::drm::V1_0::Status;
+using ::android::hardware::drm::V1_0::SubSample;
+using ::android::hardware::drm::V1_0::SubSample;
+
+using ::android::hardware::drm::V1_1::DrmMetricGroup;
+using ::android::hardware::drm::V1_1::HdcpLevel;
+using ::android::hardware::drm::V1_1::ICryptoFactory;
+using ::android::hardware::drm::V1_1::IDrmFactory;
+using ::android::hardware::drm::V1_1::IDrmPlugin;
+using ::android::hardware::drm::V1_1::SecurityLevel;
+using ::android::hardware::drm::V1_1::SecurityLevel;
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+using ::android::sp;
+
+using std::string;
+using std::unique_ptr;
+using std::random_device;
+using std::map;
+using std::mt19937;
+using std::vector;
+
+/**
+ * These clearkey tests use white box knowledge of the legacy clearkey
+ * plugin to verify that the HIDL HAL services and interfaces are working.
+ * It is not intended to verify any vendor's HAL implementation. If you
+ * are looking for vendor HAL tests, see drm_hal_vendor_test.cpp
+ */
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+// To be used in mpd to specify drm scheme for players
+static const uint8_t kClearKeyUUID[16] = {
+    0xE2, 0x71, 0x9D, 0x58, 0xA9, 0x85, 0xB3, 0xC9,
+    0x78, 0x1A, 0xB0, 0x30, 0xAF, 0x78, 0xD3, 0x0E};
+
+// Test environment for drm
+class DrmHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static DrmHidlEnvironment* Instance() {
+        static DrmHidlEnvironment* instance = new DrmHidlEnvironment;
+        return instance;
+    }
+
+    virtual void HidlSetUp() override { ALOGI("SetUp DrmHidlEnvironment"); }
+
+    virtual void HidlTearDown() override { ALOGI("TearDown DrmHidlEnvironment"); }
+
+   private:
+    DrmHidlEnvironment() {}
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(DrmHidlEnvironment);
+};
+
+
+class DrmHalClearkeyTest : public ::testing::VtsHalHidlTargetTestBase {
+public:
+    virtual void SetUp() override {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+
+        ALOGD("DrmHalClearkeyTest: Running test %s.%s", test_info->test_case_name(),
+                test_info->name());
+
+        auto manager = android::hardware::defaultServiceManager();
+        ASSERT_NE(nullptr, manager.get());
+        manager->listByInterface(IDrmFactory::descriptor,
+                [&](const hidl_vec<hidl_string> &registered) {
+                    for (const auto &instance : registered) {
+                        sp<IDrmFactory> drmFactory =
+                                ::testing::VtsHalHidlTargetTestBase::getService<IDrmFactory>(instance);
+                        drmPlugin = createDrmPlugin(drmFactory);
+                        if (drmPlugin != nullptr) {
+                            break;
+                        }
+                    }
+                }
+            );
+
+        manager->listByInterface(ICryptoFactory::descriptor,
+                [&](const hidl_vec<hidl_string> &registered) {
+                    for (const auto &instance : registered) {
+                        sp<ICryptoFactory> cryptoFactory =
+                                ::testing::VtsHalHidlTargetTestBase::getService<ICryptoFactory>(instance);
+                        cryptoPlugin = createCryptoPlugin(cryptoFactory);
+                        if (cryptoPlugin != nullptr) {
+                            break;
+                        }
+                    }
+                }
+            );
+
+        ASSERT_NE(nullptr, drmPlugin.get()) << "Can't find clearkey drm@1.1 plugin";
+        ASSERT_NE(nullptr, cryptoPlugin.get()) << "Can't find clearkey crypto@1.1 plugin";
+    }
+
+
+    virtual void TearDown() override {}
+
+    SessionId openSession();
+    void closeSession(const SessionId& sessionId);
+    hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
+    sp<IMemory> getDecryptMemory(size_t size, size_t index);
+
+  private:
+    sp<IDrmPlugin> createDrmPlugin(sp<IDrmFactory> drmFactory) {
+        if (drmFactory == nullptr) {
+            return nullptr;
+        }
+        sp<IDrmPlugin> plugin = nullptr;
+        auto res = drmFactory->createPlugin(
+                kClearKeyUUID, "",
+                        [&](Status status, const sp<drm::V1_0::IDrmPlugin>& pluginV1_0) {
+                    EXPECT_EQ(Status::OK, status);
+                    plugin = IDrmPlugin::castFrom(pluginV1_0);
+                });
+
+        if (!res.isOk()) {
+            ALOGE("createDrmPlugin remote call failed");
+        }
+        return plugin;
+    }
+
+    sp<ICryptoPlugin> createCryptoPlugin(sp<ICryptoFactory> cryptoFactory) {
+        if (cryptoFactory == nullptr) {
+            return nullptr;
+        }
+        sp<ICryptoPlugin> plugin = nullptr;
+        hidl_vec<uint8_t> initVec;
+        auto res = cryptoFactory->createPlugin(
+                kClearKeyUUID, initVec,
+                        [&](Status status, const sp<drm::V1_0::ICryptoPlugin>& pluginV1_0) {
+                    EXPECT_EQ(Status::OK, status);
+                    plugin = pluginV1_0;
+                });
+        if (!res.isOk()) {
+            ALOGE("createCryptoPlugin remote call failed");
+        }
+        return plugin;
+    }
+
+protected:
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const std::string& expected, const CT& actual) {
+     return type == DrmMetricGroup::ValueType::STRING_TYPE && expected == actual.stringValue;
+ }
+
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const int64_t expected, const CT& actual) {
+     return type == DrmMetricGroup::ValueType::INT64_TYPE && expected == actual.int64Value;
+ }
+
+ template <typename CT>
+ bool ValueEquals(DrmMetricGroup::ValueType type, const double expected, const CT& actual) {
+     return type == DrmMetricGroup::ValueType::DOUBLE_TYPE && expected == actual.doubleValue;
+ }
+
+ template <typename AT, typename VT>
+ bool ValidateMetricAttributeAndValue(const DrmMetricGroup::Metric& metric,
+                                      const std::string& attributeName, const AT& attributeValue,
+                                      const std::string& componentName, const VT& componentValue) {
+     bool validAttribute = false;
+     bool validComponent = false;
+     for (DrmMetricGroup::Attribute attribute : metric.attributes) {
+         if (attribute.name == attributeName &&
+             ValueEquals(attribute.type, attributeValue, attribute)) {
+             validAttribute = true;
+         }
+     }
+     for (DrmMetricGroup::Value value : metric.values) {
+         if (value.componentName == componentName &&
+             ValueEquals(value.type, componentValue, value)) {
+             validComponent = true;
+         }
+     }
+     return validAttribute && validComponent;
+ }
+
+ template <typename AT, typename VT>
+ bool ValidateMetricAttributeAndValue(const hidl_vec<DrmMetricGroup>& metricGroups,
+                                      const std::string& metricName,
+                                      const std::string& attributeName, const AT& attributeValue,
+                                      const std::string& componentName, const VT& componentValue) {
+     bool foundMetric = false;
+     for (const auto& group : metricGroups) {
+         for (const auto& metric : group.metrics) {
+             if (metric.name == metricName) {
+                 foundMetric = foundMetric || ValidateMetricAttributeAndValue(
+                                                  metric, attributeName, attributeValue,
+                                                  componentName, componentValue);
+             }
+         }
+     }
+     return foundMetric;
+ }
+
+ sp<IDrmPlugin> drmPlugin;
+ sp<ICryptoPlugin> cryptoPlugin;
+};
+
+
+/**
+ * Helper method to open a session and verify that a non-empty
+ * session ID is returned
+ */
+SessionId DrmHalClearkeyTest::openSession() {
+    SessionId sessionId;
+
+    auto res = drmPlugin->openSession(
+            [&sessionId](Status status, const SessionId& id) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_NE(0u, id.size());
+                sessionId = id;
+            });
+    EXPECT_OK(res);
+    return sessionId;
+}
+
+/**
+ * Helper method to close a session
+ */
+void DrmHalClearkeyTest::closeSession(const SessionId& sessionId) {
+    EXPECT_TRUE(drmPlugin->closeSession(sessionId).isOk());
+}
+
+/**
+ * Test that the plugin returns valid connected and max HDCP levels
+ */
+TEST_F(DrmHalClearkeyTest, GetHdcpLevels) {
+    auto res = drmPlugin->getHdcpLevels(
+            [&](Status status, const HdcpLevel &connectedLevel,
+                const HdcpLevel &maxLevel) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_GE(connectedLevel, HdcpLevel::HDCP_NONE);
+                EXPECT_LE(maxLevel, HdcpLevel::HDCP_NO_OUTPUT);
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Test that the plugin returns valid open and max session counts
+ */
+TEST_F(DrmHalClearkeyTest, GetSessionCounts) {
+    auto res = drmPlugin->getNumberOfSessions(
+            [&](Status status, uint32_t currentSessions,
+                    uint32_t maxSessions) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_GT(maxSessions, (uint32_t)0);
+                EXPECT_GE(currentSessions, (uint32_t)0);
+                EXPECT_LE(currentSessions, maxSessions);
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Test that the plugin returns a valid security level for
+ * a valid session
+ */
+TEST_F(DrmHalClearkeyTest, GetSecurityLevel) {
+    SessionId session = openSession();
+    auto res = drmPlugin->getSecurityLevel(session,
+            [&](Status status, SecurityLevel level) {
+                EXPECT_EQ(Status::OK, status);
+                EXPECT_GE(level, SecurityLevel::SW_SECURE_CRYPTO);
+                EXPECT_LE(level, SecurityLevel::HW_SECURE_ALL);
+            });
+    EXPECT_OK(res);
+    closeSession(session);
+}
+
+/**
+ * Test that the plugin returns the documented error
+ * when requesting the security level for an invalid sessionId
+ */
+TEST_F(DrmHalClearkeyTest, GetSecurityLevelInvalidSessionId) {
+    SessionId session;
+    auto res = drmPlugin->getSecurityLevel(session,
+            [&](Status status, SecurityLevel /*level*/) {
+                EXPECT_EQ(Status::BAD_VALUE, status);
+            });
+    EXPECT_OK(res);
+}
+
+/**
+ * Test that setting all valid security levels on a valid sessionId
+ * is supported
+ */
+TEST_F(DrmHalClearkeyTest, SetSecurityLevel) {
+    SessionId session = openSession();
+    for (uint32_t level = static_cast<uint32_t>(SecurityLevel::SW_SECURE_CRYPTO);
+         level <= static_cast<uint32_t>(SecurityLevel::HW_SECURE_ALL); level++) {
+        EXPECT_EQ(Status::OK, drmPlugin->setSecurityLevel(session, static_cast<SecurityLevel>(level)));
+
+        // check that the level got set
+        auto res = drmPlugin->getSecurityLevel(session,
+                [&](Status status, SecurityLevel readLevel) {
+                    EXPECT_EQ(Status::OK, status);
+                    EXPECT_EQ(level, static_cast<uint32_t>(readLevel));
+                });
+        EXPECT_OK(res);
+    }
+    closeSession(session);
+}
+
+/**
+ * Test that setting an invalid security level on a valid
+ * sessionId is prohibited with the documented error code.
+ */
+TEST_F(DrmHalClearkeyTest, SetInvalidSecurityLevel) {
+    SessionId session = openSession();
+    SecurityLevel level = static_cast<SecurityLevel>(
+            static_cast<uint32_t>(SecurityLevel::HW_SECURE_ALL) + 1);
+    Status status = drmPlugin->setSecurityLevel(session, level);
+    EXPECT_EQ(Status::BAD_VALUE, status);
+    closeSession(session);
+}
+
+/**
+ * Test that attempting to set security level on an invalid
+ * (empty) sessionId is prohibited with the documented error
+ * code.
+ */
+TEST_F(DrmHalClearkeyTest, SetSecurityLevelInvalidSessionId) {
+    SessionId session;
+    SecurityLevel level = SecurityLevel::SW_SECURE_CRYPTO;
+    EXPECT_EQ(Status::BAD_VALUE, drmPlugin->setSecurityLevel(session, level));
+}
+
+/**
+ * Test metrics are set appropriately for open and close operations.
+ */
+TEST_F(DrmHalClearkeyTest, GetMetricsSuccess) {
+    SessionId sessionId = openSession();
+    // The first close should be successful.
+    closeSession(sessionId);
+    // The second close should fail (not opened).
+    EXPECT_EQ(Status::ERROR_DRM_SESSION_NOT_OPENED, drmPlugin->closeSession(sessionId));
+
+    auto res = drmPlugin->getMetrics([this](Status status, hidl_vec<DrmMetricGroup> metricGroups) {
+        EXPECT_EQ(Status::OK, status);
+
+        // Verify the open_session metric.
+        EXPECT_TRUE(ValidateMetricAttributeAndValue(metricGroups, "open_session", "status",
+                                                    (int64_t)0, "count", (int64_t)1));
+        // Verify the close_session - success metric.
+        EXPECT_TRUE(ValidateMetricAttributeAndValue(metricGroups, "close_session", "status",
+                                                    (int64_t)0, "count", (int64_t)1));
+        // Verify the close_session - error metric.
+        EXPECT_TRUE(ValidateMetricAttributeAndValue(metricGroups, "close_session", "status",
+                                                    (int64_t)Status::ERROR_DRM_SESSION_NOT_OPENED,
+                                                    "count", (int64_t)1));
+    });
+}
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(DrmHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    DrmHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc b/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc
index 0f27248..f626f70 100644
--- a/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc
+++ b/dumpstate/1.0/default/android.hardware.dumpstate@1.0-service.rc
@@ -1,4 +1,4 @@
-service dumpstate-1-0 /vendor/bin/hw/android.hardware.dumpstate@1.0-service
+service vendor.dumpstate-1-0 /vendor/bin/hw/android.hardware.dumpstate@1.0-service
     class hal
     user system
     group system
diff --git a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
index 046bf56..9e866e7 100644
--- a/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
+++ b/dumpstate/1.0/vts/functional/VtsHalDumpstateV1_0TargetTest.cpp
@@ -16,6 +16,9 @@
 
 #define LOG_TAG "dumpstate_hidl_hal_test"
 
+#include <fcntl.h>
+#include <unistd.h>
+
 #include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
 #include <cutils/native_handle.h>
 #include <log/log.h>
@@ -58,50 +61,40 @@
 
 // Positive test: make sure dumpstateBoard() writes something to the FD.
 TEST_F(DumpstateHidlTest, TestOk) {
-    FILE* file = tmpfile();
-
-    ASSERT_NE(nullptr, file) << "Could not create temp file: " << strerror(errno);
+    // Index 0 corresponds to the read end of the pipe; 1 to the write end.
+    int fds[2];
+    ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
 
     native_handle_t* handle = native_handle_create(1, 0);
     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
-    handle->data[0] = fileno(file);
+    handle->data[0] = fds[1];
 
     Return<void> status = dumpstate->dumpstateBoard(handle);
     ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
 
     // Check that at least one byte was written
-    rewind(file);  // can not fail
     char buff;
-    int read = fread(&buff, sizeof(buff), 1, file);
-    ASSERT_EQ(1, read) << "dumped nothing";
-
-    EXPECT_EQ(0, fclose(file)) << errno;
+    ASSERT_EQ(1, read(fds[0], &buff, 1)) << "dumped nothing";
 
     native_handle_close(handle);
-    native_handle_delete(handle);
 }
 
 // Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
 TEST_F(DumpstateHidlTest, TestHandleWithTwoFds) {
-    FILE* file1 = tmpfile();
-    FILE* file2 = tmpfile();
-
-    ASSERT_NE(nullptr, file1) << "Could not create temp file #1: " << strerror(errno);
-    ASSERT_NE(nullptr, file2) << "Could not create temp file #2: " << strerror(errno);
+    int fds1[2];
+    int fds2[2];
+    ASSERT_EQ(0, pipe2(fds1, O_NONBLOCK)) << errno;
+    ASSERT_EQ(0, pipe2(fds2, O_NONBLOCK)) << errno;
 
     native_handle_t* handle = native_handle_create(2, 0);
     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
-    handle->data[0] = fileno(file1);
-    handle->data[1] = fileno(file2);
+    handle->data[0] = fds1[1];
+    handle->data[1] = fds2[1];
 
     Return<void> status = dumpstate->dumpstateBoard(handle);
     ASSERT_TRUE(status.isOk()) << "Status should be ok: " << status.description();
 
-    EXPECT_EQ(0, fclose(file1)) << errno;
-    EXPECT_EQ(0, fclose(file2)) << errno;
-
     native_handle_close(handle);
-    native_handle_delete(handle);
 }
 
 int main(int argc, char** argv) {
diff --git a/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
index d3f5e9d..da332c7 100644
--- a/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
+++ b/gatekeeper/1.0/default/android.hardware.gatekeeper@1.0-service.rc
@@ -1,4 +1,4 @@
-service gatekeeper-1-0 /vendor/bin/hw/android.hardware.gatekeeper@1.0-service
+service vendor.gatekeeper-1-0 /vendor/bin/hw/android.hardware.gatekeeper@1.0-service
     class hal
     user system
     group system
diff --git a/gnss/1.0/IGnssCallback.hal b/gnss/1.0/IGnssCallback.hal
index 89e5e0e..7fb38c5 100644
--- a/gnss/1.0/IGnssCallback.hal
+++ b/gnss/1.0/IGnssCallback.hal
@@ -76,9 +76,9 @@
 
     struct GnssSvInfo {
         /**
-         * Pseudo-random number for the SV, or FCN/OSN number for Glonass. The
-         * distinction is made by looking at constellation field. Values must be
-         * in the range of:
+         * Pseudo-random or satellite ID number for the satellite, a.k.a. Space Vehicle (SV), or
+         * FCN/OSN number for Glonass. The distinction is made by looking at constellation field.
+         * Values must be in the range of:
          *
          * - GNSS:    1-32
          * - SBAS:    120-151, 183-192
diff --git a/gnss/1.0/IGnssConfiguration.hal b/gnss/1.0/IGnssConfiguration.hal
index e315286..75aee7c 100644
--- a/gnss/1.0/IGnssConfiguration.hal
+++ b/gnss/1.0/IGnssConfiguration.hal
@@ -78,9 +78,13 @@
      */
 
      /**
-      * This method enables or disables emergency SUPL.
+      * This method enables or disables NI emergency SUPL restrictions.
       *
-      * @param enabled True if emergency SUPL is to be enabled.
+      * @param enabled True if the device must only accept NI Emergency SUPL requests when the
+      *                     device is truly in emergency mode (e.g. the user has dialed 911, 112,
+      *                     etc...)
+      *                False if the device must accept NI Emergency SUPL any time they are
+      *                      received
       *
       * @return success True if operation was successful.
       */
diff --git a/gnss/1.0/IGnssMeasurementCallback.hal b/gnss/1.0/IGnssMeasurementCallback.hal
index 4031664..b27c2e0 100644
--- a/gnss/1.0/IGnssMeasurementCallback.hal
+++ b/gnss/1.0/IGnssMeasurementCallback.hal
@@ -496,7 +496,7 @@
          * to L1 must be filled, and in the other all of the values related to
          * L5 must be filled.
          *
-         * If the data is available, gnssClockFlags must contain
+         * If the data is available, gnssMeasurementFlags must contain
          * HAS_CARRIER_FREQUENCY.
          */
         float carrierFrequencyHz;
@@ -508,7 +508,7 @@
          * resets in the accumulation of this value can be inferred from the
          * accumulatedDeltaRangeState flags.
          *
-         * If the data is available, gnssClockFlags must contain
+         * If the data is available, gnssMeasurementFlags must contain
          * HAS_CARRIER_CYCLES.
          */
         int64_t carrierCycles;
@@ -521,14 +521,14 @@
          * The reference frequency is given by the field 'carrierFrequencyHz'.
          * The value contains the 'carrier-phase uncertainty' in it.
          *
-         * If the data is available, gnssClockFlags must contain
+         * If the data is available, gnssMeasurementFlags must contain
          * HAS_CARRIER_PHASE.
          */
         double carrierPhase;
 
         /**
          * 1-Sigma uncertainty of the carrier-phase.
-         * If the data is available, gnssClockFlags must contain
+         * If the data is available, gnssMeasurementFlags must contain
          * HAS_CARRIER_PHASE_UNCERTAINTY.
          */
         double carrierPhaseUncertainty;
diff --git a/gnss/1.0/IGnssNavigationMessageCallback.hal b/gnss/1.0/IGnssNavigationMessageCallback.hal
index 3fdae9f..24ee708 100644
--- a/gnss/1.0/IGnssNavigationMessageCallback.hal
+++ b/gnss/1.0/IGnssNavigationMessageCallback.hal
@@ -119,7 +119,8 @@
          *
          * - For Galileo F/NAV, this refers to the page type in the range 1-6
          *
-         * - For Galileo I/NAV, this refers to the word type in the range 1-10+
+         * - For Galileo I/NAV, this refers to the word type in the range 0-10+
+         * A value of 0 is only allowed if the Satellite is transmiting a Spare Word.
          */
         int16_t submessageId;
 
diff --git a/gnss/1.0/default/Gnss.cpp b/gnss/1.0/default/Gnss.cpp
index a27cdf3..32c131c 100644
--- a/gnss/1.0/default/Gnss.cpp
+++ b/gnss/1.0/default/Gnss.cpp
@@ -508,7 +508,7 @@
         const AGpsRilInterface* agpsRilIface = static_cast<const AGpsRilInterface*>(
                 mGnssIface->get_extension(AGPS_RIL_INTERFACE));
         if (agpsRilIface == nullptr) {
-            ALOGE("%s GnssRil interface not implemented by GNSS HAL", __func__);
+            ALOGI("%s: GnssRil interface not implemented by HAL", __func__);
         } else {
             mGnssRil = new AGnssRil(agpsRilIface);
         }
@@ -528,7 +528,7 @@
                         mGnssIface->get_extension(GNSS_CONFIGURATION_INTERFACE));
 
         if (gnssConfigIface == nullptr) {
-            ALOGE("%s GnssConfiguration interface not implemented by GNSS HAL", __func__);
+            ALOGE("%s: GnssConfiguration interface not implemented by HAL", __func__);
         } else {
             mGnssConfig = new GnssConfiguration(gnssConfigIface);
         }
@@ -548,7 +548,7 @@
                         mGnssIface->get_extension(GPS_GEOFENCING_INTERFACE));
 
         if (gpsGeofencingIface == nullptr) {
-            ALOGE("%s GnssGeofencing interface not implemented by GNSS HAL", __func__);
+            ALOGE("%s: GnssGeofencing interface not implemented by HAL", __func__);
         } else {
             mGnssGeofencingIface = new GnssGeofencing(gpsGeofencingIface);
         }
@@ -567,7 +567,7 @@
         const AGpsInterface* agpsIface = static_cast<const AGpsInterface*>(
                 mGnssIface->get_extension(AGPS_INTERFACE));
         if (agpsIface == nullptr) {
-            ALOGE("%s AGnss interface not implemented by GNSS HAL", __func__);
+            ALOGE("%s: AGnss interface not implemented by HAL", __func__);
         } else {
             mAGnssIface = new AGnss(agpsIface);
         }
@@ -585,7 +585,7 @@
         const GpsNiInterface* gpsNiIface = static_cast<const GpsNiInterface*>(
                 mGnssIface->get_extension(GPS_NI_INTERFACE));
         if (gpsNiIface == nullptr) {
-            ALOGE("%s GnssNi interface not implemented by GNSS HAL", __func__);
+            ALOGI("%s: GnssNi interface not implemented by HAL", __func__);
         } else {
             mGnssNi = new GnssNi(gpsNiIface);
         }
@@ -605,7 +605,7 @@
                         mGnssIface->get_extension(GPS_MEASUREMENT_INTERFACE));
 
         if (gpsMeasurementIface == nullptr) {
-            ALOGE("%s GnssMeasurement interface not implemented by GNSS HAL", __func__);
+            ALOGE("%s: GnssMeasurement interface not implemented by HAL", __func__);
         } else {
             mGnssMeasurement = new GnssMeasurement(gpsMeasurementIface);
         }
@@ -625,8 +625,7 @@
                         mGnssIface->get_extension(GPS_NAVIGATION_MESSAGE_INTERFACE));
 
         if (gpsNavigationMessageIface == nullptr) {
-            ALOGE("%s GnssNavigationMessage interface not implemented by GNSS HAL",
-                  __func__);
+            ALOGI("%s: GnssNavigationMessage interface not implemented by HAL", __func__);
         } else {
             mGnssNavigationMessage = new GnssNavigationMessage(gpsNavigationMessageIface);
         }
@@ -646,7 +645,7 @@
                 mGnssIface->get_extension(GPS_XTRA_INTERFACE));
 
         if (gpsXtraIface == nullptr) {
-            ALOGE("%s GnssXtra interface not implemented by HAL", __func__);
+            ALOGI("%s: GnssXtra interface not implemented by HAL", __func__);
         } else {
             mGnssXtraIface = new GnssXtra(gpsXtraIface);
         }
@@ -666,7 +665,7 @@
                 mGnssIface->get_extension(GPS_DEBUG_INTERFACE));
 
         if (gpsDebugIface == nullptr) {
-            ALOGE("%s: GnssDebug interface is not implemented by HAL", __func__);
+            ALOGI("%s: GnssDebug interface not implemented by HAL", __func__);
         } else {
             mGnssDebug = new GnssDebug(gpsDebugIface);
         }
diff --git a/gnss/1.0/default/GnssUtils.cpp b/gnss/1.0/default/GnssUtils.cpp
index d9956d6..4514a21 100644
--- a/gnss/1.0/default/GnssUtils.cpp
+++ b/gnss/1.0/default/GnssUtils.cpp
@@ -51,23 +51,36 @@
     return gnssLocation;
 }
 
-GnssLocation convertToGnssLocation(FlpLocation* location) {
+GnssLocation convertToGnssLocation(FlpLocation* flpLocation) {
     GnssLocation gnssLocation = {};
-    if (location != nullptr) {
-        gnssLocation = {
-            // Bit mask applied (and 0's below) for same reason as above with GpsLocation
-            .gnssLocationFlags = static_cast<uint16_t>(location->flags & 0x1f),
-            .latitudeDegrees = location->latitude,
-            .longitudeDegrees = location->longitude,
-            .altitudeMeters = location->altitude,
-            .speedMetersPerSec = location->speed,
-            .bearingDegrees = location->bearing,
-            .horizontalAccuracyMeters = location->accuracy,
-            .verticalAccuracyMeters = 0,
-            .speedAccuracyMetersPerSecond = 0,
-            .bearingAccuracyDegrees = 0,
-            .timestamp = location->timestamp
-        };
+    if (flpLocation != nullptr) {
+        gnssLocation = {.gnssLocationFlags = 0,  // clear here and set below
+                        .latitudeDegrees = flpLocation->latitude,
+                        .longitudeDegrees = flpLocation->longitude,
+                        .altitudeMeters = flpLocation->altitude,
+                        .speedMetersPerSec = flpLocation->speed,
+                        .bearingDegrees = flpLocation->bearing,
+                        .horizontalAccuracyMeters = flpLocation->accuracy,
+                        .verticalAccuracyMeters = 0,
+                        .speedAccuracyMetersPerSecond = 0,
+                        .bearingAccuracyDegrees = 0,
+                        .timestamp = flpLocation->timestamp};
+        // FlpLocation flags different from GnssLocation flags
+        if (flpLocation->flags & FLP_LOCATION_HAS_LAT_LONG) {
+            gnssLocation.gnssLocationFlags |= GPS_LOCATION_HAS_LAT_LONG;
+        }
+        if (flpLocation->flags & FLP_LOCATION_HAS_ALTITUDE) {
+            gnssLocation.gnssLocationFlags |= GPS_LOCATION_HAS_ALTITUDE;
+        }
+        if (flpLocation->flags & FLP_LOCATION_HAS_SPEED) {
+            gnssLocation.gnssLocationFlags |= GPS_LOCATION_HAS_SPEED;
+        }
+        if (flpLocation->flags & FLP_LOCATION_HAS_BEARING) {
+            gnssLocation.gnssLocationFlags |= GPS_LOCATION_HAS_BEARING;
+        }
+        if (flpLocation->flags & FLP_LOCATION_HAS_ACCURACY) {
+            gnssLocation.gnssLocationFlags |= GPS_LOCATION_HAS_HORIZONTAL_ACCURACY;
+        }
     }
 
     return gnssLocation;
diff --git a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
index e629955..1a44d34 100644
--- a/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
+++ b/gnss/1.0/default/android.hardware.gnss@1.0-service.rc
@@ -1,4 +1,4 @@
-service gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service
+service vendor.gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service
     class hal
     user gps
     group system gps radio
diff --git a/gnss/1.1/Android.bp b/gnss/1.1/Android.bp
new file mode 100644
index 0000000..417b4f5
--- /dev/null
+++ b/gnss/1.1/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.gnss@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IGnss.hal",
+        "IGnssCallback.hal",
+        "IGnssConfiguration.hal",
+        "IGnssMeasurement.hal",
+    ],
+    interfaces: [
+        "android.hardware.gnss@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
+
diff --git a/gnss/1.1/IGnss.hal b/gnss/1.1/IGnss.hal
new file mode 100644
index 0000000..096f251
--- /dev/null
+++ b/gnss/1.1/IGnss.hal
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@1.1;
+
+import @1.0::IGnss;
+import @1.0::GnssLocation;
+
+import IGnssCallback;
+import IGnssConfiguration;
+import IGnssMeasurement;
+
+/** Represents the standard GNSS (Global Navigation Satellite System) interface. */
+interface IGnss extends @1.0::IGnss {
+    /**
+     * Opens the interface and provides the callback routines to the implementation of this
+     * interface.
+     *
+     * @param callback Callback interface for IGnss.
+     *
+     * @return success Returns true on success.
+     */
+    setCallback_1_1(IGnssCallback callback) generates (bool success);
+
+    /**
+     * Sets the GnssPositionMode parameter, its associated recurrence value,
+     * the time between fixes, requested fix accuracy, time to first fix.
+     *
+     * @param mode Parameter must be one of MS_BASED or STANDALONE. It is allowed by the platform
+     *     (and it is recommended) to fallback to MS_BASED if MS_ASSISTED is passed in, and MS_BASED
+     *     is supported.
+     * @param recurrence GNSS postion recurrence value, either periodic or single.
+     * @param minIntervalMs Represents the time between fixes in milliseconds.
+     * @param preferredAccuracyMeters Represents the requested fix accuracy in meters.
+     * @param preferredTimeMs Represents the requested time to first fix in milliseconds.
+     * @param lowPowerMode When true, HAL must make strong tradeoffs to substantially restrict power
+     *     use. Specifically, in the case of a several second long minIntervalMs, the GNSS chipset
+     *     must not, on average, run power hungry operations like RF and signal searches for more
+     *     than one second per interval, and must make exactly one call to gnssSvStatusCb(), and
+     *     either zero or one call to GnssLocationCb() at each interval. When false, HAL must
+     *     operate in the nominal mode (similar to V1.0 where this flag wasn't present) and is
+     *     expected to make power and performance tradoffs such as duty-cycling when signal
+     *     conditions are good and more active searches to reacquire GNSS signals when no signals
+     *     are present.
+     *
+     * @return success Returns true if successful.
+     */
+    setPositionMode_1_1(GnssPositionMode mode,
+                        GnssPositionRecurrence recurrence,
+                        uint32_t minIntervalMs,
+                        uint32_t preferredAccuracyMeters,
+                        uint32_t preferredTimeMs,
+                        bool lowPowerMode)
+             generates (bool success);
+
+   /**
+    * This method returns the IGnssConfiguration interface.
+    *
+    * @return gnssConfigurationIface Handle to the IGnssConfiguration interface.
+    */
+    getExtensionGnssConfiguration_1_1() generates (IGnssConfiguration gnssConfigurationIface);
+
+   /**
+    * This method returns the IGnssMeasurement interface.
+    *
+    * @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
+    */
+    getExtensionGnssMeasurement_1_1() generates (IGnssMeasurement gnssMeasurementIface);
+
+    /**
+     * Injects current location from the best available location provider.
+     *
+     * Unlike injectLocation, this method may inject a recent GNSS location from the HAL
+     * implementation, if that is the best available location known to the framework.
+     *
+     * @param location Location information from the best available location provider.
+     *
+     * @return success Returns true if successful.
+     */
+    injectBestLocation(GnssLocation location) generates (bool success);
+};
\ No newline at end of file
diff --git a/gnss/1.1/IGnssCallback.hal b/gnss/1.1/IGnssCallback.hal
new file mode 100644
index 0000000..9fd71ae
--- /dev/null
+++ b/gnss/1.1/IGnssCallback.hal
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@1.1;
+
+import @1.0::IGnssCallback;
+
+/**
+ * The interface is required for the HAL to communicate certain information
+ * like status and location info back to the platform, the platform implements
+ * the interfaces and passes a handle to the HAL.
+ */
+interface IGnssCallback extends @1.0::IGnssCallback {
+    /**
+     * Callback to inform framework of the GNSS HAL implementation model & version name.
+     *
+     * This is a user-visible string that identifies the model and version of the GNSS HAL.
+     * For example "ABC Co., Baseband Part 1234, RF Part 567, Software version 3.14.159"
+     *
+     * This must be called in response to IGnss::setCallback
+     *
+     * @param name String providing the name of the GNSS HAL implementation
+     */
+    gnssNameCb(string name);
+
+    /**
+     * Callback for requesting Location.
+     *
+     * HAL implementation shall call this when it wants the framework to provide location to assist
+     * with GNSS HAL operation. For example, to assist with time to first fix, and/or error
+     * recovery, it may ask for a location that is independent from GNSS (e.g. from the "network"
+     * LocationProvier), or to provide a Device-Based-Hybrid location to supplement A-GPS/GNSS
+     * emergency call flows managed by the GNSS HAL.
+     *
+     * @param independentFromGnss True if requesting a location that is independent from GNSS.
+     */
+    gnssRequestLocationCb(bool independentFromGnss);
+};
\ No newline at end of file
diff --git a/gnss/1.1/IGnssConfiguration.hal b/gnss/1.1/IGnssConfiguration.hal
new file mode 100644
index 0000000..105fda3
--- /dev/null
+++ b/gnss/1.1/IGnssConfiguration.hal
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@1.1;
+
+import @1.0::IGnssConfiguration;
+import @1.0::GnssConstellationType;
+
+/**
+ * Extended interface for GNSS Configuration support.
+ */
+interface IGnssConfiguration extends @1.0::IGnssConfiguration {
+    struct BlacklistedSource {
+        /**
+         * Defines the constellation of the given satellite(s).
+         */
+        GnssConstellationType constellation;
+
+        /**
+         * Satellite (space vehicle) ID number, as defined in GnssSvInfo::svid
+         *
+         * Or 0 to blacklist all svid's for the specified constellation
+         */
+        int16_t svid;
+    };
+
+    /**
+     * Injects a vector of BlacklistedSource(s) which the HAL must not use to calculate the
+     * GNSS location output.
+     *
+     * The superset of all satellite sources provided, including wildcards, in the latest call
+     * to this method, is the set of satellites sources that must not be used in calculating
+     * location.
+     *
+     * All measurements from the specified satellites, across frequency bands, are blacklisted
+     * together.
+     *
+     * If this method is never called after the IGnssConfiguration.hal connection is made on boot,
+     * or is called with an empty vector, then no satellites are to be blacklisted as a result of
+     * this API.
+     *
+     * This blacklist must be considered as an additional source of which satellites
+     * should not be trusted for location on top of existing sources of similar information
+     * such as satellite broadcast health being unhealthy and measurement outlier removal.
+     *
+     * @param blacklist The BlacklistedSource(s) of satellites the HAL must not use.
+     *
+     * @return success Whether the HAL accepts and abides by the provided blacklist.
+     */
+    setBlacklist(vec<BlacklistedSource> blacklist) generates (bool success);
+};
\ No newline at end of file
diff --git a/gnss/1.1/IGnssMeasurement.hal b/gnss/1.1/IGnssMeasurement.hal
new file mode 100644
index 0000000..75df5a8
--- /dev/null
+++ b/gnss/1.1/IGnssMeasurement.hal
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@1.1;
+
+import @1.0::IGnssMeasurement;
+import @1.0::IGnssMeasurementCallback;
+
+/**
+ * Extended interface for GNSS Measurements support.
+ */
+interface IGnssMeasurement extends @1.0::IGnssMeasurement {
+
+    /**
+     * Initializes the interface and registers the callback routines with the HAL. After a
+     * successful call to 'setCallback_1_1' the HAL must begin to provide updates at an average
+     * output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec
+     * can be tolerated.)
+     *
+     * @param callback Handle to GnssMeasurement callback interface.
+     * @param enableFullTracking If true, GNSS chipset must switch off duty cycling. In such mode
+     *     no clock discontinuities are expected and, when supported, carrier phase should be
+     *     continuous in good signal conditions. All constellations and frequency bands that the
+     *     chipset supports must be reported in this mode. The GNSS chipset is allowed to consume
+     *     more power in this mode. If false, API must behave as in HAL V1_0, optimizing power via
+     *     duty cycling, constellations and frequency limits, etc.
+     *
+     * @return initRet Returns SUCCESS if successful. Returns ERROR_ALREADY_INIT if a callback has
+     *     already been registered without a corresponding call to 'close'. Returns ERROR_GENERIC
+     *     for any other error. The HAL must not generate any other updates upon returning this
+     *     error code.
+     */
+    setCallback_1_1(IGnssMeasurementCallback callback, bool enableFullTracking)
+         generates (GnssMeasurementStatus initRet);
+
+};
diff --git a/gnss/1.1/vts/OWNERS b/gnss/1.1/vts/OWNERS
new file mode 100644
index 0000000..56648ad
--- /dev/null
+++ b/gnss/1.1/vts/OWNERS
@@ -0,0 +1,6 @@
+wyattriley@google.com
+gomo@google.com
+smalkos@google.com
+
+# VTS team
+yim@google.com
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..67ef486
--- /dev/null
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalGnssV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "gnss_hal_test.cpp",
+        "gnss_hal_test_cases.cpp",
+        "VtsHalGnssV1_1TargetTest.cpp",
+    ],
+    static_libs: [
+        "android.hardware.gnss@1.0",
+        "android.hardware.gnss@1.1",
+    ],
+}
diff --git a/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
new file mode 100644
index 0000000..9b805e4
--- /dev/null
+++ b/gnss/1.1/vts/functional/VtsHalGnssV1_1TargetTest.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
new file mode 100644
index 0000000..7e43b92
--- /dev/null
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gnss_hal_test.h>
+
+#include <chrono>
+
+// Implementations for the main test class for GNSS HAL
+GnssHalTest::GnssHalTest()
+    : info_called_count_(0),
+      capabilities_called_count_(0),
+      location_called_count_(0),
+      name_called_count_(0),
+      notify_count_(0) {}
+
+void GnssHalTest::SetUp() {
+    gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>();
+    list_gnss_sv_status_.clear();
+    ASSERT_NE(gnss_hal_, nullptr);
+}
+
+void GnssHalTest::TearDown() {
+    if (gnss_hal_ != nullptr) {
+        gnss_hal_->cleanup();
+    }
+    if (notify_count_ > 0) {
+        ALOGW("%d unprocessed callbacks discarded", notify_count_);
+    }
+}
+
+void GnssHalTest::StopAndClearLocations() {
+    auto result = gnss_hal_->stop();
+
+    EXPECT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    /*
+     * Clear notify/waiting counter, allowing up till the timeout after
+     * the last reply for final startup messages to arrive (esp. system
+     * info.)
+     */
+    while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) {
+    }
+}
+
+void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
+    const int kPreferredAccuracy = 0;  // Ideally perfect (matches GnssLocationProvider)
+    const int kPreferredTimeMsec = 0;  // Ideally immediate
+
+    auto result = gnss_hal_->setPositionMode_1_1(
+        IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
+        min_interval_msec, kPreferredAccuracy, kPreferredTimeMsec, low_power_mode);
+
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+bool GnssHalTest::StartAndGetSingleLocation() {
+    auto result = gnss_hal_->start();
+
+    EXPECT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    /*
+     * GPS signals initially optional for this test, so don't expect fast fix,
+     * or no timeout, unless signal is present
+     */
+    const int kFirstGnssLocationTimeoutSeconds = 15;
+
+    wait(kFirstGnssLocationTimeoutSeconds);
+    EXPECT_EQ(location_called_count_, 1);
+
+    if (location_called_count_ > 0) {
+        // don't require speed on first fix
+        CheckLocation(last_location_, false);
+        return true;
+    }
+    return false;
+}
+
+void GnssHalTest::CheckLocation(GnssLocation& location, bool check_speed) {
+    bool check_more_accuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017);
+
+    EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG);
+    EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE);
+    if (check_speed) {
+        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED);
+    }
+    EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY);
+    // New uncertainties available in O must be provided,
+    // at least when paired with modern hardware (2017+)
+    if (check_more_accuracies) {
+        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY);
+        if (check_speed) {
+            EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY);
+            if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+                EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY);
+            }
+        }
+    }
+    EXPECT_GE(location.latitudeDegrees, -90.0);
+    EXPECT_LE(location.latitudeDegrees, 90.0);
+    EXPECT_GE(location.longitudeDegrees, -180.0);
+    EXPECT_LE(location.longitudeDegrees, 180.0);
+    EXPECT_GE(location.altitudeMeters, -1000.0);
+    EXPECT_LE(location.altitudeMeters, 30000.0);
+    if (check_speed) {
+        EXPECT_GE(location.speedMetersPerSec, 0.0);
+        EXPECT_LE(location.speedMetersPerSec, 5.0);  // VTS tests are stationary.
+
+        // Non-zero speeds must be reported with an associated bearing
+        if (location.speedMetersPerSec > 0.0) {
+            EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING);
+        }
+    }
+
+    /*
+     * Tolerating some especially high values for accuracy estimate, in case of
+     * first fix with especially poor geometry (happens occasionally)
+     */
+    EXPECT_GT(location.horizontalAccuracyMeters, 0.0);
+    EXPECT_LE(location.horizontalAccuracyMeters, 250.0);
+
+    /*
+     * Some devices may define bearing as -180 to +180, others as 0 to 360.
+     * Both are okay & understandable.
+     */
+    if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+        EXPECT_GE(location.bearingDegrees, -180.0);
+        EXPECT_LE(location.bearingDegrees, 360.0);
+    }
+    if (location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+        EXPECT_GT(location.verticalAccuracyMeters, 0.0);
+        EXPECT_LE(location.verticalAccuracyMeters, 500.0);
+    }
+    if (location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+        EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0);
+        EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0);
+    }
+    if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+        EXPECT_GT(location.bearingAccuracyDegrees, 0.0);
+        EXPECT_LE(location.bearingAccuracyDegrees, 360.0);
+    }
+
+    // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+)
+    EXPECT_GT(location.timestamp, 1.48e12);
+}
+
+void GnssHalTest::StartAndCheckLocations(int count) {
+    const int kMinIntervalMsec = 500;
+    const int kLocationTimeoutSubsequentSec = 2;
+    const bool kLowPowerMode = true;
+
+    SetPositionMode(kMinIntervalMsec, kLowPowerMode);
+
+    EXPECT_TRUE(StartAndGetSingleLocation());
+
+    for (int i = 1; i < count; i++) {
+        EXPECT_EQ(std::cv_status::no_timeout, wait(kLocationTimeoutSubsequentSec));
+        EXPECT_EQ(location_called_count_, i + 1);
+        // Don't cause confusion by checking details if no location yet
+        if (location_called_count_ > 0) {
+            // Should be more than 1 location by now, but if not, still don't check first fix speed
+            CheckLocation(last_location_, location_called_count_ > 1);
+        }
+    }
+}
+
+void GnssHalTest::notify() {
+    std::unique_lock<std::mutex> lock(mtx_);
+    notify_count_++;
+    cv_.notify_one();
+}
+
+std::cv_status GnssHalTest::wait(int timeout_seconds) {
+    std::unique_lock<std::mutex> lock(mtx_);
+
+    auto status = std::cv_status::no_timeout;
+    while (notify_count_ == 0) {
+        status = cv_.wait_for(lock, std::chrono::seconds(timeout_seconds));
+        if (status == std::cv_status::timeout) return status;
+    }
+    notify_count_--;
+    return status;
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
+    const IGnssCallback::GnssSystemInfo& info) {
+    ALOGI("Info received, year %d", info.yearOfHw);
+    parent_.info_called_count_++;
+    parent_.last_info_ = info;
+    parent_.notify();
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
+    ALOGI("Capabilities received %d", capabilities);
+    parent_.capabilities_called_count_++;
+    parent_.last_capabilities_ = capabilities;
+    parent_.notify();
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
+    ALOGI("Name received: %s", name.c_str());
+    parent_.name_called_count_++;
+    parent_.last_name_ = name;
+    parent_.notify();
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssLocationCb(const GnssLocation& location) {
+    ALOGI("Location received");
+    parent_.location_called_count_++;
+    parent_.last_location_ = location;
+    parent_.notify();
+    return Void();
+}
+
+Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(
+    const IGnssCallback::GnssSvStatus& svStatus) {
+    ALOGI("GnssSvStatus received");
+    parent_.list_gnss_sv_status_.emplace_back(svStatus);
+    return Void();
+}
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
new file mode 100644
index 0000000..6aab3cb
--- /dev/null
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GNSS_HAL_TEST_H_
+#define GNSS_HAL_TEST_H_
+
+#define LOG_TAG "VtsHalGnssV1_1TargetTest"
+
+#include <android/hardware/gnss/1.1/IGnss.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <condition_variable>
+#include <list>
+#include <mutex>
+
+using android::hardware::Return;
+using android::hardware::Void;
+
+using android::hardware::gnss::V1_0::GnssLocation;
+
+using android::hardware::gnss::V1_1::IGnss;
+using android::hardware::gnss::V1_1::IGnssCallback;
+using android::hardware::gnss::V1_0::GnssLocationFlags;
+
+using android::sp;
+
+#define TIMEOUT_SEC 2  // for basic commands/responses
+
+// The main test class for GNSS HAL.
+class GnssHalTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    GnssHalTest();
+
+    virtual void SetUp() override;
+
+    virtual void TearDown() override;
+
+    /* Used as a mechanism to inform the test that a callback has occurred */
+    void notify();
+
+    /* Test code calls this function to wait for a callback */
+    std::cv_status wait(int timeout_seconds);
+
+    /* Callback class for data & Event. */
+    class GnssCallback : public IGnssCallback {
+       public:
+        GnssHalTest& parent_;
+
+        GnssCallback(GnssHalTest& parent) : parent_(parent){};
+
+        virtual ~GnssCallback() = default;
+
+        // Dummy callback handlers
+        Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override {
+            return Void();
+        }
+        Return<void> gnssNmeaCb(int64_t /* timestamp */,
+                                const android::hardware::hidl_string& /* nmea */) override {
+            return Void();
+        }
+        Return<void> gnssAcquireWakelockCb() override { return Void(); }
+        Return<void> gnssReleaseWakelockCb() override { return Void(); }
+        Return<void> gnssRequestLocationCb(bool /* independentFromGnss */) override {
+            return Void();
+        }
+        Return<void> gnssRequestTimeCb() override { return Void(); }
+        // Actual (test) callback handlers
+        Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+        Return<void> gnssLocationCb(const GnssLocation& location) override;
+        Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+        Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
+        Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
+    };
+
+    /*
+     * StartAndGetSingleLocation:
+     * Helper function to get one Location and check fields
+     *
+     * returns  true if a location was successfully generated
+     */
+    bool StartAndGetSingleLocation();
+
+    /*
+     * CheckLocation:
+     *   Helper function to vet Location fields
+     */
+    void CheckLocation(GnssLocation& location, bool check_speed);
+
+    /*
+     * StartAndCheckLocations:
+     *   Helper function to collect, and check a number of
+     *   normal ~1Hz locations.
+     *
+     *   Note this leaves the Location request active, to enable Stop call vs. other call
+     *   reordering tests.
+     */
+    void StartAndCheckLocations(int count);
+
+    /*
+     * StopAndClearLocations:
+     * Helper function to stop locations, and clear any remaining notifications
+     */
+    void StopAndClearLocations();
+
+    /*
+     * SetPositionMode:
+     * Helper function to set positioning mode and verify output
+     */
+    void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
+
+    sp<IGnss> gnss_hal_;         // GNSS HAL to call into
+    sp<IGnssCallback> gnss_cb_;  // Primary callback interface
+
+    /* Count of calls to set the following items, and the latest item (used by
+     * test.)
+     */
+    int info_called_count_;
+    IGnssCallback::GnssSystemInfo last_info_;
+    uint32_t last_capabilities_;
+    int capabilities_called_count_;
+    int location_called_count_;
+    GnssLocation last_location_;
+    list<IGnssCallback::GnssSvStatus> list_gnss_sv_status_;
+
+    int name_called_count_;
+    android::hardware::hidl_string last_name_;
+
+   private:
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int notify_count_;
+};
+
+#endif  // GNSS_HAL_TEST_H_
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
new file mode 100644
index 0000000..0b27922
--- /dev/null
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gnss_hal_test.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+
+using android::hardware::hidl_vec;
+
+using android::hardware::gnss::V1_0::GnssConstellationType;
+using android::hardware::gnss::V1_0::GnssLocation;
+using android::hardware::gnss::V1_0::IGnssDebug;
+using android::hardware::gnss::V1_1::IGnssConfiguration;
+using android::hardware::gnss::V1_1::IGnssMeasurement;
+
+/*
+ * SetupTeardownCreateCleanup:
+ * Requests the gnss HAL then calls cleanup
+ *
+ * Empty test fixture to verify basic Setup & Teardown
+ */
+TEST_F(GnssHalTest, SetupTeardownCreateCleanup) {}
+
+/*
+ * SetCallbackResponses:
+ * Sets up the callback, awaits the capability, info & name
+ */
+TEST_F(GnssHalTest, SetCallbackResponses) {
+    gnss_cb_ = new GnssCallback(*this);
+    ASSERT_NE(gnss_cb_, nullptr);
+
+    auto result = gnss_hal_->setCallback_1_1(gnss_cb_);
+    if (!result.isOk()) {
+        ALOGE("result of failed setCallback %s", result.description().c_str());
+    }
+
+    ASSERT_TRUE(result.isOk());
+    ASSERT_TRUE(result);
+
+    /*
+     * All capabilities, name and systemInfo callbacks should trigger
+     */
+    EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+    EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+    EXPECT_EQ(std::cv_status::no_timeout, wait(TIMEOUT_SEC));
+
+    EXPECT_EQ(capabilities_called_count_, 1);
+    EXPECT_EQ(info_called_count_, 1);
+    EXPECT_EQ(name_called_count_, 1);
+}
+
+/*
+ * TestGnssMeasurementCallback:
+ * Gets the GnssMeasurementExtension and verify that it returns an actual extension.
+ */
+TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
+    auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_1_1();
+    ASSERT_TRUE(gnssMeasurement.isOk());
+    if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
+        sp<IGnssMeasurement> iGnssMeas = gnssMeasurement;
+        EXPECT_NE(iGnssMeas, nullptr);
+    }
+}
+
+/*
+ * GetLocationLowPower:
+ * Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
+ * between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
+ * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
+ * each received location.
+ */
+TEST_F(GnssHalTest, GetLocationLowPower) {
+    const int kMinIntervalMsec = 5000;
+    const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) + 1;
+    const int kNoLocationPeriodSec = 2;
+    const int kLocationsToCheck = 5;
+    const bool kLowPowerMode = true;
+
+    SetPositionMode(kMinIntervalMsec, kLowPowerMode);
+
+    EXPECT_TRUE(StartAndGetSingleLocation());
+
+    for (int i = 1; i < kLocationsToCheck; i++) {
+        // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
+        // ensure that no location is received yet
+        wait(kNoLocationPeriodSec);
+        EXPECT_EQ(location_called_count_, i);
+        EXPECT_EQ(std::cv_status::no_timeout,
+                  wait(kLocationTimeoutSubsequentSec - kNoLocationPeriodSec));
+        EXPECT_EQ(location_called_count_, i + 1);
+        CheckLocation(last_location_, true);
+    }
+
+    StopAndClearLocations();
+}
+
+/*
+ * FindStrongFrequentSource:
+ *
+ * Search through a GnssSvStatus list for the strongest satellite observed enough times
+ *
+ * returns the strongest source,
+ *         or a source with constellation == UNKNOWN if none are found sufficient times
+ */
+
+IGnssConfiguration::BlacklistedSource FindStrongFrequentSource(
+    const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status, const int min_observations) {
+    struct ComparableBlacklistedSource {
+        IGnssConfiguration::BlacklistedSource id;
+
+        bool operator<(const ComparableBlacklistedSource& compare) const {
+            return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
+                                                    (id.constellation < compare.id.constellation)));
+        }
+    };
+
+    struct SignalCounts {
+        int observations;
+        float max_cn0_dbhz;
+    };
+
+    std::map<ComparableBlacklistedSource, SignalCounts> mapSignals;
+
+    for (const auto& gnss_sv_status : list_gnss_sv_status) {
+        for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
+            const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
+            if (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) {
+                ComparableBlacklistedSource source;
+                source.id.svid = gnss_sv.svid;
+                source.id.constellation = gnss_sv.constellation;
+
+                const auto& itSignal = mapSignals.find(source);
+                if (itSignal == mapSignals.end()) {
+                    SignalCounts counts;
+                    counts.observations = 1;
+                    counts.max_cn0_dbhz = gnss_sv.cN0Dbhz;
+                    mapSignals.insert(
+                        std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
+                } else {
+                    itSignal->second.observations++;
+                    if (itSignal->second.max_cn0_dbhz < gnss_sv.cN0Dbhz) {
+                        itSignal->second.max_cn0_dbhz = gnss_sv.cN0Dbhz;
+                    }
+                }
+            }
+        }
+    }
+
+    float max_cn0_dbhz_with_sufficient_count = 0.;
+    int total_observation_count = 0;
+    int blacklisted_source_count_observation = 0;
+
+    ComparableBlacklistedSource source_to_blacklist;  // initializes to zero = UNKNOWN constellation
+    for (auto const& pairSignal : mapSignals) {
+        total_observation_count += pairSignal.second.observations;
+        if ((pairSignal.second.observations >= min_observations) &&
+            (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
+            source_to_blacklist = pairSignal.first;
+            blacklisted_source_count_observation = pairSignal.second.observations;
+            max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
+        }
+    }
+    ALOGD(
+        "Among %d observations, chose svid %d, constellation %d, "
+        "with %d observations at %.1f max CNo",
+        total_observation_count, source_to_blacklist.id.svid,
+        (int)source_to_blacklist.id.constellation, blacklisted_source_count_observation,
+        max_cn0_dbhz_with_sufficient_count);
+
+    return source_to_blacklist.id;
+}
+
+/*
+ * BlacklistIndividualSatellites:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for common satellites (strongest and one other.)
+ * 2a & b) Turns off location, and blacklists common satellites.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use those satellites.
+ * 4a & b) Turns off location, and send in empty blacklist.
+ * 5) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does re-use at least the previously strongest satellite
+ */
+TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+    const int kLocationsToAwait = 3;
+
+    StartAndCheckLocations(kLocationsToAwait);
+
+    EXPECT_GE((int)list_gnss_sv_status_.size(), kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+          kLocationsToAwait);
+
+    /*
+     * Identify strongest SV seen at least kLocationsToAwait -1 times
+     * Why -1?  To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
+     * observability (one epoch RF null)
+     */
+
+    IGnssConfiguration::BlacklistedSource source_to_blacklist =
+        FindStrongFrequentSource(list_gnss_sv_status_, kLocationsToAwait - 1);
+    EXPECT_NE(source_to_blacklist.constellation, GnssConstellationType::UNKNOWN);
+
+    // Stop locations, blacklist the common SV
+    StopAndClearLocations();
+
+    auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
+    ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+    sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
+    sources.resize(1);
+    sources[0] = source_to_blacklist;
+
+    auto result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    // retry and ensure satellite not used
+    list_gnss_sv_status_.clear();
+
+    location_called_count_ = 0;
+    StartAndCheckLocations(kLocationsToAwait);
+
+    EXPECT_GE((int)list_gnss_sv_status_.size(), kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+          kLocationsToAwait);
+    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+        for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
+            const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
+            EXPECT_FALSE((gnss_sv.svid == source_to_blacklist.svid) &&
+                         (gnss_sv.constellation == source_to_blacklist.constellation) &&
+                         (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clear blacklist and restart - this time updating the blacklist while location is still on
+    sources.resize(0);
+
+    result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    location_called_count_ = 0;
+    StopAndClearLocations();
+    list_gnss_sv_status_.clear();
+
+    StartAndCheckLocations(kLocationsToAwait);
+
+    EXPECT_GE((int)list_gnss_sv_status_.size(), kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+          kLocationsToAwait);
+
+    bool strongest_sv_is_reobserved = false;
+    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+        for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
+            const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
+            if ((gnss_sv.svid == source_to_blacklist.svid) &&
+                (gnss_sv.constellation == source_to_blacklist.constellation) &&
+                (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
+                strongest_sv_is_reobserved = true;
+                break;
+            }
+        }
+        if (strongest_sv_is_reobserved) break;
+    }
+    EXPECT_TRUE(strongest_sv_is_reobserved);
+}
+
+/*
+ * BlacklistConstellation:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Turns off location, and blacklist first non-GPS constellations.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use any constellation but GPS.
+ * 4a & b) Clean up by turning off location, and send in empty blacklist.
+ */
+TEST_F(GnssHalTest, BlacklistConstellation) {
+    const int kLocationsToAwait = 3;
+
+    StartAndCheckLocations(kLocationsToAwait);
+
+    EXPECT_GE((int)list_gnss_sv_status_.size(), kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+          kLocationsToAwait);
+
+    // Find first non-GPS constellation to blacklist
+    GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
+    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+        for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
+            const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
+            if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
+                (gnss_sv.constellation != GnssConstellationType::UNKNOWN) &&
+                (gnss_sv.constellation != GnssConstellationType::GPS)) {
+                // found a non-GPS constellation
+                constellation_to_blacklist = gnss_sv.constellation;
+                break;
+            }
+        }
+        if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
+            break;
+        }
+    }
+
+    if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
+        ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+        // Proceed functionally to blacklist something.
+        constellation_to_blacklist = GnssConstellationType::GLONASS;
+    }
+    IGnssConfiguration::BlacklistedSource source_to_blacklist;
+    source_to_blacklist.constellation = constellation_to_blacklist;
+    source_to_blacklist.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
+    ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+    sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
+    sources.resize(1);
+    sources[0] = source_to_blacklist;
+
+    auto result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    // retry and ensure constellation not used
+    list_gnss_sv_status_.clear();
+
+    location_called_count_ = 0;
+    StartAndCheckLocations(kLocationsToAwait);
+
+    EXPECT_GE((int)list_gnss_sv_status_.size(), kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+          kLocationsToAwait);
+    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+        for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
+            const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
+            EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
+                         (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clean up
+    StopAndClearLocations();
+    sources.resize(0);
+    result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+/*
+ * InjectBestLocation
+ *
+ * Ensure successfully injecting a location.
+ */
+TEST_F(GnssHalTest, InjectBestLocation) {
+    GnssLocation gnssLocation = {.gnssLocationFlags = 0,  // set below
+                                 .latitudeDegrees = 43.0,
+                                 .longitudeDegrees = -180,
+                                 .altitudeMeters = 1000,
+                                 .speedMetersPerSec = 0,
+                                 .bearingDegrees = 0,
+                                 .horizontalAccuracyMeters = 0.1,
+                                 .verticalAccuracyMeters = 0.1,
+                                 .speedAccuracyMetersPerSecond = 0.1,
+                                 .bearingAccuracyDegrees = 0.1,
+                                 .timestamp = 1534567890123L};
+    gnssLocation.gnssLocationFlags |=
+        GnssLocationFlags::HAS_LAT_LONG | GnssLocationFlags::HAS_ALTITUDE |
+        GnssLocationFlags::HAS_SPEED | GnssLocationFlags::HAS_HORIZONTAL_ACCURACY |
+        GnssLocationFlags::HAS_VERTICAL_ACCURACY | GnssLocationFlags::HAS_SPEED_ACCURACY |
+        GnssLocationFlags::HAS_BEARING | GnssLocationFlags::HAS_BEARING_ACCURACY;
+
+    CheckLocation(gnssLocation, true);
+
+    auto result = gnss_hal_->injectBestLocation(gnssLocation);
+
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+/*
+ * GnssDebugValuesSanityTest:
+ * Ensures that GnssDebug values make sense.
+ */
+TEST_F(GnssHalTest, GnssDebugValuesSanityTest) {
+    auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
+    ASSERT_TRUE(gnssDebug.isOk());
+    if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
+        sp<IGnssDebug> iGnssDebug = gnssDebug;
+        EXPECT_NE(iGnssDebug, nullptr);
+
+        IGnssDebug::DebugData data;
+        iGnssDebug->getDebugData(
+            [&data](const IGnssDebug::DebugData& debugData) { data = debugData; });
+
+        if (data.position.valid) {
+            EXPECT_GE(data.position.latitudeDegrees, -90);
+            EXPECT_LE(data.position.latitudeDegrees, 90);
+
+            EXPECT_GE(data.position.longitudeDegrees, -180);
+            EXPECT_LE(data.position.longitudeDegrees, 180);
+
+            EXPECT_GE(data.position.altitudeMeters, -1000);  // Dead Sea: -414m
+            EXPECT_LE(data.position.altitudeMeters, 20000);  // Mount Everest: 8850m
+
+            EXPECT_GE(data.position.speedMetersPerSec, 0);
+            EXPECT_LE(data.position.speedMetersPerSec, 600);
+
+            EXPECT_GE(data.position.bearingDegrees, -360);
+            EXPECT_LE(data.position.bearingDegrees, 360);
+
+            EXPECT_GE(data.position.horizontalAccuracyMeters, 0);
+            EXPECT_LE(data.position.horizontalAccuracyMeters, 20000000);
+
+            EXPECT_GE(data.position.verticalAccuracyMeters, 0);
+            EXPECT_LE(data.position.verticalAccuracyMeters, 20000);
+
+            EXPECT_GE(data.position.speedAccuracyMetersPerSecond, 0);
+            EXPECT_LE(data.position.speedAccuracyMetersPerSecond, 500);
+
+            EXPECT_GE(data.position.bearingAccuracyDegrees, 0);
+            EXPECT_LE(data.position.bearingAccuracyDegrees, 180);
+
+            EXPECT_GE(data.position.ageSeconds, 0);
+        }
+
+        EXPECT_GE(data.time.timeEstimate, 1514764800000);  // Jan 01 2018 00:00:00
+        EXPECT_GT(data.time.timeUncertaintyNs, 0);
+        EXPECT_GT(data.time.frequencyUncertaintyNsPerSec, 0);
+    }
+}
diff --git a/graphics/allocator/2.0/Android.bp b/graphics/allocator/2.0/Android.bp
index 0b0722e..50b474e 100644
--- a/graphics/allocator/2.0/Android.bp
+++ b/graphics/allocator/2.0/Android.bp
@@ -5,7 +5,6 @@
     root: "android.hardware",
     vndk: {
         enabled: true,
-        support_system_process: true,
     },
     srcs: [
         "IAllocator.hal",
diff --git a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
index 70f2ef8..6eee71f 100644
--- a/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
+++ b/graphics/allocator/2.0/default/android.hardware.graphics.allocator@2.0-service.rc
@@ -1,4 +1,4 @@
-service gralloc-2-0 /vendor/bin/hw/android.hardware.graphics.allocator@2.0-service
+service vendor.gralloc-2-0 /vendor/bin/hw/android.hardware.graphics.allocator@2.0-service
     class hal animation
     user system
     group graphics drmrpc
diff --git a/graphics/common/1.1/Android.bp b/graphics/common/1.1/Android.bp
new file mode 100644
index 0000000..c319d80
--- /dev/null
+++ b/graphics/common/1.1/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.common@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.0",
+    ],
+    types: [
+        "BufferUsage",
+        "Dataspace",
+        "PixelFormat",
+    ],
+    gen_java: true,
+    gen_java_constants: true,
+}
+
diff --git a/graphics/common/1.1/types.hal b/graphics/common/1.1/types.hal
new file mode 100644
index 0000000..b917d5e
--- /dev/null
+++ b/graphics/common/1.1/types.hal
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common@1.1;
+
+import @1.0::PixelFormat;
+import @1.0::BufferUsage;
+import @1.0::Dataspace;
+
+/**
+ * Pixel formats for graphics buffers.
+ */
+@export(name="android_pixel_format_v1_1_t", value_prefix="HAL_PIXEL_FORMAT_",
+        export_parent="false")
+enum PixelFormat : @1.0::PixelFormat {
+    /**
+     * 16-bit format that has a single 16-bit depth component.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    DEPTH_16           = 0x30,
+
+    /**
+     * 32-bit format that has a single 24-bit depth component and, optionally,
+     * 8 bits that are unused.
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     */
+    DEPTH_24           = 0x31,
+
+    /**
+     * 32-bit format that has a 24-bit depth component and an 8-bit stencil
+     * component packed into 32-bits.
+     *
+     * The depth component values are unsigned normalized to the range [0, 1],
+     * whose interpretation is defined by the dataspace. The stencil values are
+     * unsigned integers, whose interpretation is defined by the dataspace.
+     */
+    DEPTH_24_STENCIL_8  = 0x32,
+
+    /**
+     * 32-bit format that has a single 32-bit depth component.
+     *
+     * The component values are signed floats, whose interpretation is defined
+     * by the dataspace.
+     */
+    DEPTH_32F           = 0x33,
+
+    /**
+     * Two-component format that has a 32-bit depth component, an 8-bit stencil
+     * component, and optionally 24-bits unused.
+     *
+     * The depth component values are signed floats, whose interpretation is
+     * defined by the dataspace. The stencil bits are unsigned integers, whose
+     * interpretation is defined by the dataspace.
+     */
+    DEPTH_32F_STENCIL_8 = 0x34,
+
+    /**
+     * 8-bit format that has a single 8-bit stencil component.
+     *
+     * The component values are unsigned integers, whose interpretation is
+     * defined by the dataspace.
+     */
+    STENCIL_8           = 0x35,
+
+    /**
+     * P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
+     * followed immediately by a Wx(H/2) CbCr plane. Each sample is
+     * represented by a 16-bit little-endian value, with the lower 6 bits set
+     * to zero.
+     *
+     * This format assumes
+     * - an even height
+     * - a vertical stride equal to the height
+     *
+     *   stride_in_bytes = stride * 2
+     *   y_size = stride_in_bytes * height
+     *   cbcr_size = stride_in_bytes * (height / 2)
+     *   cb_offset = y_size
+     *   cr_offset = cb_offset + 2
+     *
+     * This format must be accepted by the allocator when used with the
+     * following usage flags:
+     *
+     *    - BufferUsage::VIDEO_*
+     *    - BufferUsage::CPU_*
+     *    - BufferUsage::GPU_TEXTURE
+     *
+     * The component values are unsigned normalized to the range [0, 1], whose
+     * interpretation is defined by the dataspace.
+     *
+     * This format is appropriate for 10bit video content.
+     *
+     * Buffers with this format must be locked with IMapper::lockYCbCr
+     * or with IMapper::lock.
+     */
+    YCBCR_P010          = 0x36,
+};
+
+/**
+ * Buffer usage definitions.
+ */
+enum BufferUsage : @1.0::BufferUsage {
+    /** buffer is used as a cube map texture */
+    GPU_CUBE_MAP          = 1ULL << 25,
+
+    /** buffer contains a complete mipmap hierarchy */
+    GPU_MIPMAP_COMPLETE   = 1ULL << 26,
+
+    /** bits 27 and 32-47 must be zero and are reserved for future versions */
+};
+
+@export(name="android_dataspace_v1_1_t", value_prefix="HAL_DATASPACE_",
+        export_parent="false")
+enum Dataspace : @1.0::Dataspace {
+    /**
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard
+     * limited range is the preferred / normative definition for BT.2020
+     */
+    BT2020_ITU = STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_LIMITED,
+
+    BT2020_ITU_PQ = STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED,
+};
diff --git a/graphics/composer/2.1/default/Android.bp b/graphics/composer/2.1/default/Android.bp
index 140e50e..b46a1de 100644
--- a/graphics/composer/2.1/default/Android.bp
+++ b/graphics/composer/2.1/default/Android.bp
@@ -17,6 +17,9 @@
         "libsync",
         "libutils",
     ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
 }
 
 cc_library_shared {
@@ -41,6 +44,9 @@
         "libhwc2on1adapter",
         "libhwc2onfbadapter",
     ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
 }
 
 cc_binary {
@@ -65,10 +71,3 @@
         "libutils",
     ],
 }
-
-cc_library_static {
-    name: "libhwcomposer-command-buffer",
-    defaults: ["hidl_defaults"],
-    shared_libs: ["android.hardware.graphics.composer@2.1"],
-    export_include_dirs: ["."],
-}
diff --git a/graphics/composer/2.1/default/ComposerClient.cpp b/graphics/composer/2.1/default/ComposerClient.cpp
index 4e6dd4f..0fcb9de 100644
--- a/graphics/composer/2.1/default/ComposerClient.cpp
+++ b/graphics/composer/2.1/default/ComposerClient.cpp
@@ -19,9 +19,8 @@
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <log/log.h>
 
-#include "ComposerClient.h"
 #include "ComposerBase.h"
-#include "IComposerCommandBuffer.h"
+#include "ComposerClient.h"
 
 namespace android {
 namespace hardware {
@@ -299,10 +298,17 @@
     Error err = mHal.createLayer(display, &layer);
     if (err == Error::NONE) {
         std::lock_guard<std::mutex> lock(mDisplayDataMutex);
-
         auto dpy = mDisplayData.find(display);
-        auto ly = dpy->second.Layers.emplace(layer, LayerBuffers()).first;
-        ly->second.Buffers.resize(bufferSlotCount);
+        // The display entry may have already been removed by onHotplug.
+        if (dpy != mDisplayData.end()) {
+            auto ly = dpy->second.Layers.emplace(layer, LayerBuffers()).first;
+            ly->second.Buffers.resize(bufferSlotCount);
+        } else {
+            err = Error::BAD_DISPLAY;
+            // Note: We do not destroy the layer on this error as the hotplug
+            // disconnect invalidates the display id. The implementation should
+            // ensure all layers for the display are destroyed.
+        }
     }
 
     hidl_cb(err, layer);
@@ -316,7 +322,10 @@
         std::lock_guard<std::mutex> lock(mDisplayDataMutex);
 
         auto dpy = mDisplayData.find(display);
-        dpy->second.Layers.erase(layer);
+        // The display entry may have already been removed by onHotplug.
+        if (dpy != mDisplayData.end()) {
+            dpy->second.Layers.erase(layer);
+        }
     }
 
     return err;
diff --git a/graphics/composer/2.1/default/ComposerClient.h b/graphics/composer/2.1/default/ComposerClient.h
index fc5c223..104ed5a 100644
--- a/graphics/composer/2.1/default/ComposerClient.h
+++ b/graphics/composer/2.1/default/ComposerClient.h
@@ -21,8 +21,8 @@
 #include <unordered_map>
 #include <vector>
 
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
 #include <hardware/hwcomposer2.h>
-#include "IComposerCommandBuffer.h"
 #include "ComposerBase.h"
 
 namespace android {
diff --git a/graphics/composer/2.1/default/IComposerCommandBuffer.h b/graphics/composer/2.1/default/IComposerCommandBuffer.h
deleted file mode 100644
index 058709c..0000000
--- a/graphics/composer/2.1/default/IComposerCommandBuffer.h
+++ /dev/null
@@ -1,881 +0,0 @@
-/*
- * Copyright 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_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
-#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
-
-#ifndef LOG_TAG
-#warn "IComposerCommandBuffer.h included without LOG_TAG"
-#endif
-
-#undef LOG_NDEBUG
-#define LOG_NDEBUG 0
-
-#include <algorithm>
-#include <limits>
-#include <memory>
-#include <vector>
-
-#include <inttypes.h>
-#include <string.h>
-
-#include <android/hardware/graphics/composer/2.1/IComposer.h>
-#include <log/log.h>
-#include <sync/sync.h>
-#include <fmq/MessageQueue.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-
-using android::hardware::graphics::common::V1_0::ColorTransform;
-using android::hardware::graphics::common::V1_0::Dataspace;
-using android::hardware::graphics::common::V1_0::Transform;
-using android::hardware::MessageQueue;
-
-using CommandQueueType = MessageQueue<uint32_t, kSynchronizedReadWrite>;
-
-// This class helps build a command queue.  Note that all sizes/lengths are in
-// units of uint32_t's.
-class CommandWriterBase {
-public:
-    CommandWriterBase(uint32_t initialMaxSize)
-        : mDataMaxSize(initialMaxSize)
-    {
-        mData = std::make_unique<uint32_t[]>(mDataMaxSize);
-        reset();
-    }
-
-    virtual ~CommandWriterBase()
-    {
-        reset();
-    }
-
-    void reset()
-    {
-        mDataWritten = 0;
-        mCommandEnd = 0;
-
-        // handles in mDataHandles are owned by the caller
-        mDataHandles.clear();
-
-        // handles in mTemporaryHandles are owned by the writer
-        for (auto handle : mTemporaryHandles) {
-            native_handle_close(handle);
-            native_handle_delete(handle);
-        }
-        mTemporaryHandles.clear();
-    }
-
-    IComposerClient::Command getCommand(uint32_t offset)
-    {
-        uint32_t val = (offset < mDataWritten) ? mData[offset] : 0;
-        return static_cast<IComposerClient::Command>(val &
-                static_cast<uint32_t>(IComposerClient::Command::OPCODE_MASK));
-    }
-
-    bool writeQueue(bool* outQueueChanged, uint32_t* outCommandLength,
-            hidl_vec<hidl_handle>* outCommandHandles)
-    {
-        // After data are written to the queue, it may not be read by the
-        // remote reader when
-        //
-        //  - the writer does not send them (because of other errors)
-        //  - the hwbinder transaction fails
-        //  - the reader does not read them (because of other errors)
-        //
-        // Discard the stale data here.
-        size_t staleDataSize = mQueue ? mQueue->availableToRead() : 0;
-        if (staleDataSize > 0) {
-            ALOGW("discarding stale data from message queue");
-            CommandQueueType::MemTransaction tx;
-            if (mQueue->beginRead(staleDataSize, &tx)) {
-                mQueue->commitRead(staleDataSize);
-            }
-        }
-
-        // write data to queue, optionally resizing it
-        if (mQueue && (mDataMaxSize <= mQueue->getQuantumCount())) {
-            if (!mQueue->write(mData.get(), mDataWritten)) {
-                ALOGE("failed to write commands to message queue");
-                return false;
-            }
-
-            *outQueueChanged = false;
-        } else {
-            auto newQueue = std::make_unique<CommandQueueType>(mDataMaxSize);
-            if (!newQueue->isValid() ||
-                    !newQueue->write(mData.get(), mDataWritten)) {
-                ALOGE("failed to prepare a new message queue ");
-                return false;
-            }
-
-            mQueue = std::move(newQueue);
-            *outQueueChanged = true;
-        }
-
-        *outCommandLength = mDataWritten;
-        outCommandHandles->setToExternal(
-                const_cast<hidl_handle*>(mDataHandles.data()),
-                mDataHandles.size());
-
-        return true;
-    }
-
-    const MQDescriptorSync<uint32_t>* getMQDescriptor() const
-    {
-        return (mQueue) ? mQueue->getDesc() : nullptr;
-    }
-
-    static constexpr uint16_t kSelectDisplayLength = 2;
-    void selectDisplay(Display display)
-    {
-        beginCommand(IComposerClient::Command::SELECT_DISPLAY,
-                kSelectDisplayLength);
-        write64(display);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSelectLayerLength = 2;
-    void selectLayer(Layer layer)
-    {
-        beginCommand(IComposerClient::Command::SELECT_LAYER,
-                kSelectLayerLength);
-        write64(layer);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetErrorLength = 2;
-    void setError(uint32_t location, Error error)
-    {
-        beginCommand(IComposerClient::Command::SET_ERROR, kSetErrorLength);
-        write(location);
-        writeSigned(static_cast<int32_t>(error));
-        endCommand();
-    }
-
-    static constexpr uint32_t kPresentOrValidateDisplayResultLength = 1;
-    void setPresentOrValidateResult(uint32_t  state) {
-       beginCommand(IComposerClient::Command::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT, kPresentOrValidateDisplayResultLength);
-       write(state);
-       endCommand();
-    }
-
-    void setChangedCompositionTypes(const std::vector<Layer>& layers,
-            const std::vector<IComposerClient::Composition>& types)
-    {
-        size_t totalLayers = std::min(layers.size(), types.size());
-        size_t currentLayer = 0;
-
-        while (currentLayer < totalLayers) {
-            size_t count = std::min(totalLayers - currentLayer,
-                    static_cast<size_t>(kMaxLength) / 3);
-
-            beginCommand(
-                    IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES,
-                    count * 3);
-            for (size_t i = 0; i < count; i++) {
-                write64(layers[currentLayer + i]);
-                writeSigned(static_cast<int32_t>(types[currentLayer + i]));
-            }
-            endCommand();
-
-            currentLayer += count;
-        }
-    }
-
-    void setDisplayRequests(uint32_t displayRequestMask,
-            const std::vector<Layer>& layers,
-            const std::vector<uint32_t>& layerRequestMasks)
-    {
-        size_t totalLayers = std::min(layers.size(),
-                layerRequestMasks.size());
-        size_t currentLayer = 0;
-
-        while (currentLayer < totalLayers) {
-            size_t count = std::min(totalLayers - currentLayer,
-                    static_cast<size_t>(kMaxLength - 1) / 3);
-
-            beginCommand(IComposerClient::Command::SET_DISPLAY_REQUESTS,
-                    1 + count * 3);
-            write(displayRequestMask);
-            for (size_t i = 0; i < count; i++) {
-                write64(layers[currentLayer + i]);
-                write(static_cast<int32_t>(layerRequestMasks[currentLayer + i]));
-            }
-            endCommand();
-
-            currentLayer += count;
-        }
-    }
-
-    static constexpr uint16_t kSetPresentFenceLength = 1;
-    void setPresentFence(int presentFence)
-    {
-        beginCommand(IComposerClient::Command::SET_PRESENT_FENCE,
-                kSetPresentFenceLength);
-        writeFence(presentFence);
-        endCommand();
-    }
-
-    void setReleaseFences(const std::vector<Layer>& layers,
-            const std::vector<int>& releaseFences)
-    {
-        size_t totalLayers = std::min(layers.size(), releaseFences.size());
-        size_t currentLayer = 0;
-
-        while (currentLayer < totalLayers) {
-            size_t count = std::min(totalLayers - currentLayer,
-                    static_cast<size_t>(kMaxLength) / 3);
-
-            beginCommand(IComposerClient::Command::SET_RELEASE_FENCES,
-                    count * 3);
-            for (size_t i = 0; i < count; i++) {
-                write64(layers[currentLayer + i]);
-                writeFence(releaseFences[currentLayer + i]);
-            }
-            endCommand();
-
-            currentLayer += count;
-        }
-    }
-
-    static constexpr uint16_t kSetColorTransformLength = 17;
-    void setColorTransform(const float* matrix, ColorTransform hint)
-    {
-        beginCommand(IComposerClient::Command::SET_COLOR_TRANSFORM,
-                kSetColorTransformLength);
-        for (int i = 0; i < 16; i++) {
-            writeFloat(matrix[i]);
-        }
-        writeSigned(static_cast<int32_t>(hint));
-        endCommand();
-    }
-
-    void setClientTarget(uint32_t slot, const native_handle_t* target,
-            int acquireFence, Dataspace dataspace,
-            const std::vector<IComposerClient::Rect>& damage)
-    {
-        bool doWrite = (damage.size() <= (kMaxLength - 4) / 4);
-        size_t length = 4 + ((doWrite) ? damage.size() * 4 : 0);
-
-        beginCommand(IComposerClient::Command::SET_CLIENT_TARGET, length);
-        write(slot);
-        writeHandle(target, true);
-        writeFence(acquireFence);
-        writeSigned(static_cast<int32_t>(dataspace));
-        // When there are too many rectangles in the damage region and doWrite
-        // is false, we write no rectangle at all which means the entire
-        // client target is damaged.
-        if (doWrite) {
-            writeRegion(damage);
-        }
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetOutputBufferLength = 3;
-    void setOutputBuffer(uint32_t slot, const native_handle_t* buffer,
-            int releaseFence)
-    {
-        beginCommand(IComposerClient::Command::SET_OUTPUT_BUFFER,
-                kSetOutputBufferLength);
-        write(slot);
-        writeHandle(buffer, true);
-        writeFence(releaseFence);
-        endCommand();
-    }
-
-    static constexpr uint16_t kValidateDisplayLength = 0;
-    void validateDisplay()
-    {
-        beginCommand(IComposerClient::Command::VALIDATE_DISPLAY,
-                kValidateDisplayLength);
-        endCommand();
-    }
-
-    static constexpr uint16_t kPresentOrValidateDisplayLength = 0;
-    void presentOrvalidateDisplay()
-    {
-        beginCommand(IComposerClient::Command::PRESENT_OR_VALIDATE_DISPLAY,
-                     kPresentOrValidateDisplayLength);
-        endCommand();
-    }
-
-    static constexpr uint16_t kAcceptDisplayChangesLength = 0;
-    void acceptDisplayChanges()
-    {
-        beginCommand(IComposerClient::Command::ACCEPT_DISPLAY_CHANGES,
-                kAcceptDisplayChangesLength);
-        endCommand();
-    }
-
-    static constexpr uint16_t kPresentDisplayLength = 0;
-    void presentDisplay()
-    {
-        beginCommand(IComposerClient::Command::PRESENT_DISPLAY,
-                kPresentDisplayLength);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerCursorPositionLength = 2;
-    void setLayerCursorPosition(int32_t x, int32_t y)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_CURSOR_POSITION,
-                kSetLayerCursorPositionLength);
-        writeSigned(x);
-        writeSigned(y);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerBufferLength = 3;
-    void setLayerBuffer(uint32_t slot, const native_handle_t* buffer,
-            int acquireFence)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_BUFFER,
-                kSetLayerBufferLength);
-        write(slot);
-        writeHandle(buffer, true);
-        writeFence(acquireFence);
-        endCommand();
-    }
-
-    void setLayerSurfaceDamage(
-            const std::vector<IComposerClient::Rect>& damage)
-    {
-        bool doWrite = (damage.size() <= kMaxLength / 4);
-        size_t length = (doWrite) ? damage.size() * 4 : 0;
-
-        beginCommand(IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE,
-                length);
-        // When there are too many rectangles in the damage region and doWrite
-        // is false, we write no rectangle at all which means the entire
-        // layer is damaged.
-        if (doWrite) {
-            writeRegion(damage);
-        }
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerBlendModeLength = 1;
-    void setLayerBlendMode(IComposerClient::BlendMode mode)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_BLEND_MODE,
-                kSetLayerBlendModeLength);
-        writeSigned(static_cast<int32_t>(mode));
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerColorLength = 1;
-    void setLayerColor(IComposerClient::Color color)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_COLOR,
-                kSetLayerColorLength);
-        writeColor(color);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerCompositionTypeLength = 1;
-    void setLayerCompositionType(IComposerClient::Composition type)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE,
-                kSetLayerCompositionTypeLength);
-        writeSigned(static_cast<int32_t>(type));
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerDataspaceLength = 1;
-    void setLayerDataspace(Dataspace dataspace)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_DATASPACE,
-                kSetLayerDataspaceLength);
-        writeSigned(static_cast<int32_t>(dataspace));
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerDisplayFrameLength = 4;
-    void setLayerDisplayFrame(const IComposerClient::Rect& frame)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_DISPLAY_FRAME,
-                kSetLayerDisplayFrameLength);
-        writeRect(frame);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerPlaneAlphaLength = 1;
-    void setLayerPlaneAlpha(float alpha)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_PLANE_ALPHA,
-                kSetLayerPlaneAlphaLength);
-        writeFloat(alpha);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerSidebandStreamLength = 1;
-    void setLayerSidebandStream(const native_handle_t* stream)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM,
-                kSetLayerSidebandStreamLength);
-        writeHandle(stream);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerSourceCropLength = 4;
-    void setLayerSourceCrop(const IComposerClient::FRect& crop)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_SOURCE_CROP,
-                kSetLayerSourceCropLength);
-        writeFRect(crop);
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerTransformLength = 1;
-    void setLayerTransform(Transform transform)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_TRANSFORM,
-                kSetLayerTransformLength);
-        writeSigned(static_cast<int32_t>(transform));
-        endCommand();
-    }
-
-    void setLayerVisibleRegion(
-            const std::vector<IComposerClient::Rect>& visible)
-    {
-        bool doWrite = (visible.size() <= kMaxLength / 4);
-        size_t length = (doWrite) ? visible.size() * 4 : 0;
-
-        beginCommand(IComposerClient::Command::SET_LAYER_VISIBLE_REGION,
-                length);
-        // When there are too many rectangles in the visible region and
-        // doWrite is false, we write no rectangle at all which means the
-        // entire layer is visible.
-        if (doWrite) {
-            writeRegion(visible);
-        }
-        endCommand();
-    }
-
-    static constexpr uint16_t kSetLayerZOrderLength = 1;
-    void setLayerZOrder(uint32_t z)
-    {
-        beginCommand(IComposerClient::Command::SET_LAYER_Z_ORDER,
-                kSetLayerZOrderLength);
-        write(z);
-        endCommand();
-    }
-
-protected:
-    void beginCommand(IComposerClient::Command command, uint16_t length)
-    {
-        if (mCommandEnd) {
-            LOG_FATAL("endCommand was not called before command 0x%x",
-                    command);
-        }
-
-        growData(1 + length);
-        write(static_cast<uint32_t>(command) | length);
-
-        mCommandEnd = mDataWritten + length;
-    }
-
-    void endCommand()
-    {
-        if (!mCommandEnd) {
-            LOG_FATAL("beginCommand was not called");
-        } else if (mDataWritten > mCommandEnd) {
-            LOG_FATAL("too much data written");
-            mDataWritten = mCommandEnd;
-        } else if (mDataWritten < mCommandEnd) {
-            LOG_FATAL("too little data written");
-            while (mDataWritten < mCommandEnd) {
-                write(0);
-            }
-        }
-
-        mCommandEnd = 0;
-    }
-
-    void write(uint32_t val)
-    {
-        mData[mDataWritten++] = val;
-    }
-
-    void writeSigned(int32_t val)
-    {
-        memcpy(&mData[mDataWritten++], &val, sizeof(val));
-    }
-
-    void writeFloat(float val)
-    {
-        memcpy(&mData[mDataWritten++], &val, sizeof(val));
-    }
-
-    void write64(uint64_t val)
-    {
-        uint32_t lo = static_cast<uint32_t>(val & 0xffffffff);
-        uint32_t hi = static_cast<uint32_t>(val >> 32);
-        write(lo);
-        write(hi);
-    }
-
-    void writeRect(const IComposerClient::Rect& rect)
-    {
-        writeSigned(rect.left);
-        writeSigned(rect.top);
-        writeSigned(rect.right);
-        writeSigned(rect.bottom);
-    }
-
-    void writeRegion(const std::vector<IComposerClient::Rect>& region)
-    {
-        for (const auto& rect : region) {
-            writeRect(rect);
-        }
-    }
-
-    void writeFRect(const IComposerClient::FRect& rect)
-    {
-        writeFloat(rect.left);
-        writeFloat(rect.top);
-        writeFloat(rect.right);
-        writeFloat(rect.bottom);
-    }
-
-    void writeColor(const IComposerClient::Color& color)
-    {
-        write((color.r <<  0) |
-              (color.g <<  8) |
-              (color.b << 16) |
-              (color.a << 24));
-    }
-
-    // ownership of handle is not transferred
-    void writeHandle(const native_handle_t* handle, bool useCache)
-    {
-        if (!handle) {
-            writeSigned(static_cast<int32_t>((useCache) ?
-                        IComposerClient::HandleIndex::CACHED :
-                        IComposerClient::HandleIndex::EMPTY));
-            return;
-        }
-
-        mDataHandles.push_back(handle);
-        writeSigned(mDataHandles.size() - 1);
-    }
-
-    void writeHandle(const native_handle_t* handle)
-    {
-        writeHandle(handle, false);
-    }
-
-    // ownership of fence is transferred
-    void writeFence(int fence)
-    {
-        native_handle_t* handle = nullptr;
-        if (fence >= 0) {
-            handle = getTemporaryHandle(1, 0);
-            if (handle) {
-                handle->data[0] = fence;
-            } else {
-                ALOGW("failed to get temporary handle for fence %d", fence);
-                sync_wait(fence, -1);
-                close(fence);
-            }
-        }
-
-        writeHandle(handle);
-    }
-
-    native_handle_t* getTemporaryHandle(int numFds, int numInts)
-    {
-        native_handle_t* handle = native_handle_create(numFds, numInts);
-        if (handle) {
-            mTemporaryHandles.push_back(handle);
-        }
-        return handle;
-    }
-
-    static constexpr uint16_t kMaxLength =
-        std::numeric_limits<uint16_t>::max();
-
-private:
-    void growData(uint32_t grow)
-    {
-        uint32_t newWritten = mDataWritten + grow;
-        if (newWritten < mDataWritten) {
-            LOG_ALWAYS_FATAL("buffer overflowed; data written %" PRIu32
-                    ", growing by %" PRIu32, mDataWritten, grow);
-        }
-
-        if (newWritten <= mDataMaxSize) {
-            return;
-        }
-
-        uint32_t newMaxSize = mDataMaxSize << 1;
-        if (newMaxSize < newWritten) {
-            newMaxSize = newWritten;
-        }
-
-        auto newData = std::make_unique<uint32_t[]>(newMaxSize);
-        std::copy_n(mData.get(), mDataWritten, newData.get());
-        mDataMaxSize = newMaxSize;
-        mData = std::move(newData);
-    }
-
-    uint32_t mDataMaxSize;
-    std::unique_ptr<uint32_t[]> mData;
-
-    uint32_t mDataWritten;
-    // end offset of the current command
-    uint32_t mCommandEnd;
-
-    std::vector<hidl_handle> mDataHandles;
-    std::vector<native_handle_t *> mTemporaryHandles;
-
-    std::unique_ptr<CommandQueueType> mQueue;
-};
-
-// This class helps parse a command queue.  Note that all sizes/lengths are in
-// units of uint32_t's.
-class CommandReaderBase {
-public:
-    CommandReaderBase() : mDataMaxSize(0)
-    {
-        reset();
-    }
-
-    bool setMQDescriptor(const MQDescriptorSync<uint32_t>& descriptor)
-    {
-        mQueue = std::make_unique<CommandQueueType>(descriptor, false);
-        if (mQueue->isValid()) {
-            return true;
-        } else {
-            mQueue = nullptr;
-            return false;
-        }
-    }
-
-    bool readQueue(uint32_t commandLength,
-            const hidl_vec<hidl_handle>& commandHandles)
-    {
-        if (!mQueue) {
-            return false;
-        }
-
-        auto quantumCount = mQueue->getQuantumCount();
-        if (mDataMaxSize < quantumCount) {
-            mDataMaxSize = quantumCount;
-            mData = std::make_unique<uint32_t[]>(mDataMaxSize);
-        }
-
-        if (commandLength > mDataMaxSize ||
-                !mQueue->read(mData.get(), commandLength)) {
-            ALOGE("failed to read commands from message queue");
-            return false;
-        }
-
-        mDataSize = commandLength;
-        mDataRead = 0;
-        mCommandBegin = 0;
-        mCommandEnd = 0;
-        mDataHandles.setToExternal(
-                const_cast<hidl_handle*>(commandHandles.data()),
-                commandHandles.size());
-
-        return true;
-    }
-
-    void reset()
-    {
-        mDataSize = 0;
-        mDataRead = 0;
-        mCommandBegin = 0;
-        mCommandEnd = 0;
-        mDataHandles.setToExternal(nullptr, 0);
-    }
-
-protected:
-    bool isEmpty() const
-    {
-        return (mDataRead >= mDataSize);
-    }
-
-    bool beginCommand(IComposerClient::Command* outCommand,
-            uint16_t* outLength)
-    {
-        if (mCommandEnd) {
-            LOG_FATAL("endCommand was not called for last command");
-        }
-
-        constexpr uint32_t opcode_mask =
-            static_cast<uint32_t>(IComposerClient::Command::OPCODE_MASK);
-        constexpr uint32_t length_mask =
-            static_cast<uint32_t>(IComposerClient::Command::LENGTH_MASK);
-
-        uint32_t val = read();
-        *outCommand = static_cast<IComposerClient::Command>(
-                val & opcode_mask);
-        *outLength = static_cast<uint16_t>(val & length_mask);
-
-        if (mDataRead + *outLength > mDataSize) {
-            ALOGE("command 0x%x has invalid command length %" PRIu16,
-                    *outCommand, *outLength);
-            // undo the read() above
-            mDataRead--;
-            return false;
-        }
-
-        mCommandEnd = mDataRead + *outLength;
-
-        return true;
-    }
-
-    void endCommand()
-    {
-        if (!mCommandEnd) {
-            LOG_FATAL("beginCommand was not called");
-        } else if (mDataRead > mCommandEnd) {
-            LOG_FATAL("too much data read");
-            mDataRead = mCommandEnd;
-        } else if (mDataRead < mCommandEnd) {
-            LOG_FATAL("too little data read");
-            mDataRead = mCommandEnd;
-        }
-
-        mCommandBegin = mCommandEnd;
-        mCommandEnd = 0;
-    }
-
-    uint32_t getCommandLoc() const
-    {
-        return mCommandBegin;
-    }
-
-    uint32_t read()
-    {
-        return mData[mDataRead++];
-    }
-
-    int32_t readSigned()
-    {
-        int32_t val;
-        memcpy(&val, &mData[mDataRead++], sizeof(val));
-        return val;
-    }
-
-    float readFloat()
-    {
-        float val;
-        memcpy(&val, &mData[mDataRead++], sizeof(val));
-        return val;
-    }
-
-    uint64_t read64()
-    {
-        uint32_t lo = read();
-        uint32_t hi = read();
-        return (static_cast<uint64_t>(hi) << 32) | lo;
-    }
-
-    IComposerClient::Color readColor()
-    {
-        uint32_t val = read();
-        return IComposerClient::Color{
-            static_cast<uint8_t>((val >>  0) & 0xff),
-            static_cast<uint8_t>((val >>  8) & 0xff),
-            static_cast<uint8_t>((val >> 16) & 0xff),
-            static_cast<uint8_t>((val >> 24) & 0xff),
-        };
-    }
-
-    // ownership of handle is not transferred
-    const native_handle_t* readHandle(bool* outUseCache)
-    {
-        const native_handle_t* handle = nullptr;
-
-        int32_t index = readSigned();
-        switch (index) {
-        case static_cast<int32_t>(IComposerClient::HandleIndex::EMPTY):
-            *outUseCache = false;
-            break;
-        case static_cast<int32_t>(IComposerClient::HandleIndex::CACHED):
-            *outUseCache = true;
-            break;
-        default:
-            if (static_cast<size_t>(index) < mDataHandles.size()) {
-                handle = mDataHandles[index].getNativeHandle();
-            } else {
-                ALOGE("invalid handle index %zu", static_cast<size_t>(index));
-            }
-            *outUseCache = false;
-            break;
-        }
-
-        return handle;
-    }
-
-    const native_handle_t* readHandle()
-    {
-        bool useCache;
-        return readHandle(&useCache);
-    }
-
-    // ownership of fence is transferred
-    int readFence()
-    {
-        auto handle = readHandle();
-        if (!handle || handle->numFds == 0) {
-            return -1;
-        }
-
-        if (handle->numFds != 1) {
-            ALOGE("invalid fence handle with %d fds", handle->numFds);
-            return -1;
-        }
-
-        int fd = dup(handle->data[0]);
-        if (fd < 0) {
-            ALOGW("failed to dup fence %d", handle->data[0]);
-            sync_wait(handle->data[0], -1);
-            fd = -1;
-        }
-
-        return fd;
-    }
-
-private:
-    std::unique_ptr<CommandQueueType> mQueue;
-    uint32_t mDataMaxSize;
-    std::unique_ptr<uint32_t[]> mData;
-
-    uint32_t mDataSize;
-    uint32_t mDataRead;
-
-    // begin/end offsets of the current command
-    uint32_t mCommandBegin;
-    uint32_t mCommandEnd;
-
-    hidl_vec<hidl_handle> mDataHandles;
-};
-
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
diff --git a/graphics/composer/2.1/default/OWNERS b/graphics/composer/2.1/default/OWNERS
index 3aa5fa1..4714be2 100644
--- a/graphics/composer/2.1/default/OWNERS
+++ b/graphics/composer/2.1/default/OWNERS
@@ -1,4 +1,5 @@
 # Graphics team
+courtneygo@google.com
 jessehall@google.com
 olv@google.com
 stoza@google.com
diff --git a/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
index 51b0e3b..3b6710b 100644
--- a/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
+++ b/graphics/composer/2.1/default/android.hardware.graphics.composer@2.1-service.rc
@@ -1,4 +1,4 @@
-service hwcomposer-2-1 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service
+service vendor.hwcomposer-2-1 /vendor/bin/hw/android.hardware.graphics.composer@2.1-service
     class hal animation
     user system
     group graphics drmrpc
diff --git a/graphics/composer/2.1/utils/OWNERS b/graphics/composer/2.1/utils/OWNERS
new file mode 100644
index 0000000..d515a23
--- /dev/null
+++ b/graphics/composer/2.1/utils/OWNERS
@@ -0,0 +1,4 @@
+courtneygo@google.com
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/composer/2.1/utils/command-buffer/Android.bp b/graphics/composer/2.1/utils/command-buffer/Android.bp
new file mode 100644
index 0000000..e8d41c2
--- /dev/null
+++ b/graphics/composer/2.1/utils/command-buffer/Android.bp
@@ -0,0 +1,7 @@
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.1-command-buffer",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: ["android.hardware.graphics.composer@2.1"],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
new file mode 100644
index 0000000..df529ec
--- /dev/null
+++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
@@ -0,0 +1,759 @@
+/*
+ * Copyright 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_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
+#define ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
+
+#ifndef LOG_TAG
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <fmq/MessageQueue.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::MessageQueue;
+
+using CommandQueueType = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+// This class helps build a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase {
+   public:
+    CommandWriterBase(uint32_t initialMaxSize) : mDataMaxSize(initialMaxSize) {
+        mData = std::make_unique<uint32_t[]>(mDataMaxSize);
+        reset();
+    }
+
+    virtual ~CommandWriterBase() { reset(); }
+
+    void reset() {
+        mDataWritten = 0;
+        mCommandEnd = 0;
+
+        // handles in mDataHandles are owned by the caller
+        mDataHandles.clear();
+
+        // handles in mTemporaryHandles are owned by the writer
+        for (auto handle : mTemporaryHandles) {
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+        mTemporaryHandles.clear();
+    }
+
+    IComposerClient::Command getCommand(uint32_t offset) {
+        uint32_t val = (offset < mDataWritten) ? mData[offset] : 0;
+        return static_cast<IComposerClient::Command>(
+            val & static_cast<uint32_t>(IComposerClient::Command::OPCODE_MASK));
+    }
+
+    bool writeQueue(bool* outQueueChanged, uint32_t* outCommandLength,
+                    hidl_vec<hidl_handle>* outCommandHandles) {
+        if (mDataWritten == 0) {
+            *outQueueChanged = false;
+            *outCommandLength = 0;
+            outCommandHandles->setToExternal(nullptr, 0);
+            return true;
+        }
+
+        // After data are written to the queue, it may not be read by the
+        // remote reader when
+        //
+        //  - the writer does not send them (because of other errors)
+        //  - the hwbinder transaction fails
+        //  - the reader does not read them (because of other errors)
+        //
+        // Discard the stale data here.
+        size_t staleDataSize = mQueue ? mQueue->availableToRead() : 0;
+        if (staleDataSize > 0) {
+            ALOGW("discarding stale data from message queue");
+            CommandQueueType::MemTransaction tx;
+            if (mQueue->beginRead(staleDataSize, &tx)) {
+                mQueue->commitRead(staleDataSize);
+            }
+        }
+
+        // write data to queue, optionally resizing it
+        if (mQueue && (mDataMaxSize <= mQueue->getQuantumCount())) {
+            if (!mQueue->write(mData.get(), mDataWritten)) {
+                ALOGE("failed to write commands to message queue");
+                return false;
+            }
+
+            *outQueueChanged = false;
+        } else {
+            auto newQueue = std::make_unique<CommandQueueType>(mDataMaxSize);
+            if (!newQueue->isValid() || !newQueue->write(mData.get(), mDataWritten)) {
+                ALOGE("failed to prepare a new message queue ");
+                return false;
+            }
+
+            mQueue = std::move(newQueue);
+            *outQueueChanged = true;
+        }
+
+        *outCommandLength = mDataWritten;
+        outCommandHandles->setToExternal(const_cast<hidl_handle*>(mDataHandles.data()),
+                                         mDataHandles.size());
+
+        return true;
+    }
+
+    const MQDescriptorSync<uint32_t>* getMQDescriptor() const {
+        return (mQueue) ? mQueue->getDesc() : nullptr;
+    }
+
+    static constexpr uint16_t kSelectDisplayLength = 2;
+    void selectDisplay(Display display) {
+        beginCommand(IComposerClient::Command::SELECT_DISPLAY, kSelectDisplayLength);
+        write64(display);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSelectLayerLength = 2;
+    void selectLayer(Layer layer) {
+        beginCommand(IComposerClient::Command::SELECT_LAYER, kSelectLayerLength);
+        write64(layer);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetErrorLength = 2;
+    void setError(uint32_t location, Error error) {
+        beginCommand(IComposerClient::Command::SET_ERROR, kSetErrorLength);
+        write(location);
+        writeSigned(static_cast<int32_t>(error));
+        endCommand();
+    }
+
+    static constexpr uint32_t kPresentOrValidateDisplayResultLength = 1;
+    void setPresentOrValidateResult(uint32_t state) {
+        beginCommand(IComposerClient::Command::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT,
+                     kPresentOrValidateDisplayResultLength);
+        write(state);
+        endCommand();
+    }
+
+    void setChangedCompositionTypes(const std::vector<Layer>& layers,
+                                    const std::vector<IComposerClient::Composition>& types) {
+        size_t totalLayers = std::min(layers.size(), types.size());
+        size_t currentLayer = 0;
+
+        while (currentLayer < totalLayers) {
+            size_t count =
+                std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength) / 3);
+
+            beginCommand(IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES, count * 3);
+            for (size_t i = 0; i < count; i++) {
+                write64(layers[currentLayer + i]);
+                writeSigned(static_cast<int32_t>(types[currentLayer + i]));
+            }
+            endCommand();
+
+            currentLayer += count;
+        }
+    }
+
+    void setDisplayRequests(uint32_t displayRequestMask, const std::vector<Layer>& layers,
+                            const std::vector<uint32_t>& layerRequestMasks) {
+        size_t totalLayers = std::min(layers.size(), layerRequestMasks.size());
+        size_t currentLayer = 0;
+
+        while (currentLayer < totalLayers) {
+            size_t count =
+                std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength - 1) / 3);
+
+            beginCommand(IComposerClient::Command::SET_DISPLAY_REQUESTS, 1 + count * 3);
+            write(displayRequestMask);
+            for (size_t i = 0; i < count; i++) {
+                write64(layers[currentLayer + i]);
+                write(static_cast<int32_t>(layerRequestMasks[currentLayer + i]));
+            }
+            endCommand();
+
+            currentLayer += count;
+        }
+    }
+
+    static constexpr uint16_t kSetPresentFenceLength = 1;
+    void setPresentFence(int presentFence) {
+        beginCommand(IComposerClient::Command::SET_PRESENT_FENCE, kSetPresentFenceLength);
+        writeFence(presentFence);
+        endCommand();
+    }
+
+    void setReleaseFences(const std::vector<Layer>& layers, const std::vector<int>& releaseFences) {
+        size_t totalLayers = std::min(layers.size(), releaseFences.size());
+        size_t currentLayer = 0;
+
+        while (currentLayer < totalLayers) {
+            size_t count =
+                std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength) / 3);
+
+            beginCommand(IComposerClient::Command::SET_RELEASE_FENCES, count * 3);
+            for (size_t i = 0; i < count; i++) {
+                write64(layers[currentLayer + i]);
+                writeFence(releaseFences[currentLayer + i]);
+            }
+            endCommand();
+
+            currentLayer += count;
+        }
+    }
+
+    static constexpr uint16_t kSetColorTransformLength = 17;
+    void setColorTransform(const float* matrix, ColorTransform hint) {
+        beginCommand(IComposerClient::Command::SET_COLOR_TRANSFORM, kSetColorTransformLength);
+        for (int i = 0; i < 16; i++) {
+            writeFloat(matrix[i]);
+        }
+        writeSigned(static_cast<int32_t>(hint));
+        endCommand();
+    }
+
+    void setClientTarget(uint32_t slot, const native_handle_t* target, int acquireFence,
+                         Dataspace dataspace, const std::vector<IComposerClient::Rect>& damage) {
+        bool doWrite = (damage.size() <= (kMaxLength - 4) / 4);
+        size_t length = 4 + ((doWrite) ? damage.size() * 4 : 0);
+
+        beginCommand(IComposerClient::Command::SET_CLIENT_TARGET, length);
+        write(slot);
+        writeHandle(target, true);
+        writeFence(acquireFence);
+        writeSigned(static_cast<int32_t>(dataspace));
+        // When there are too many rectangles in the damage region and doWrite
+        // is false, we write no rectangle at all which means the entire
+        // client target is damaged.
+        if (doWrite) {
+            writeRegion(damage);
+        }
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetOutputBufferLength = 3;
+    void setOutputBuffer(uint32_t slot, const native_handle_t* buffer, int releaseFence) {
+        beginCommand(IComposerClient::Command::SET_OUTPUT_BUFFER, kSetOutputBufferLength);
+        write(slot);
+        writeHandle(buffer, true);
+        writeFence(releaseFence);
+        endCommand();
+    }
+
+    static constexpr uint16_t kValidateDisplayLength = 0;
+    void validateDisplay() {
+        beginCommand(IComposerClient::Command::VALIDATE_DISPLAY, kValidateDisplayLength);
+        endCommand();
+    }
+
+    static constexpr uint16_t kPresentOrValidateDisplayLength = 0;
+    void presentOrvalidateDisplay() {
+        beginCommand(IComposerClient::Command::PRESENT_OR_VALIDATE_DISPLAY,
+                     kPresentOrValidateDisplayLength);
+        endCommand();
+    }
+
+    static constexpr uint16_t kAcceptDisplayChangesLength = 0;
+    void acceptDisplayChanges() {
+        beginCommand(IComposerClient::Command::ACCEPT_DISPLAY_CHANGES, kAcceptDisplayChangesLength);
+        endCommand();
+    }
+
+    static constexpr uint16_t kPresentDisplayLength = 0;
+    void presentDisplay() {
+        beginCommand(IComposerClient::Command::PRESENT_DISPLAY, kPresentDisplayLength);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerCursorPositionLength = 2;
+    void setLayerCursorPosition(int32_t x, int32_t y) {
+        beginCommand(IComposerClient::Command::SET_LAYER_CURSOR_POSITION,
+                     kSetLayerCursorPositionLength);
+        writeSigned(x);
+        writeSigned(y);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerBufferLength = 3;
+    void setLayerBuffer(uint32_t slot, const native_handle_t* buffer, int acquireFence) {
+        beginCommand(IComposerClient::Command::SET_LAYER_BUFFER, kSetLayerBufferLength);
+        write(slot);
+        writeHandle(buffer, true);
+        writeFence(acquireFence);
+        endCommand();
+    }
+
+    void setLayerSurfaceDamage(const std::vector<IComposerClient::Rect>& damage) {
+        bool doWrite = (damage.size() <= kMaxLength / 4);
+        size_t length = (doWrite) ? damage.size() * 4 : 0;
+
+        beginCommand(IComposerClient::Command::SET_LAYER_SURFACE_DAMAGE, length);
+        // When there are too many rectangles in the damage region and doWrite
+        // is false, we write no rectangle at all which means the entire
+        // layer is damaged.
+        if (doWrite) {
+            writeRegion(damage);
+        }
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerBlendModeLength = 1;
+    void setLayerBlendMode(IComposerClient::BlendMode mode) {
+        beginCommand(IComposerClient::Command::SET_LAYER_BLEND_MODE, kSetLayerBlendModeLength);
+        writeSigned(static_cast<int32_t>(mode));
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerColorLength = 1;
+    void setLayerColor(IComposerClient::Color color) {
+        beginCommand(IComposerClient::Command::SET_LAYER_COLOR, kSetLayerColorLength);
+        writeColor(color);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerCompositionTypeLength = 1;
+    void setLayerCompositionType(IComposerClient::Composition type) {
+        beginCommand(IComposerClient::Command::SET_LAYER_COMPOSITION_TYPE,
+                     kSetLayerCompositionTypeLength);
+        writeSigned(static_cast<int32_t>(type));
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerDataspaceLength = 1;
+    void setLayerDataspace(Dataspace dataspace) {
+        beginCommand(IComposerClient::Command::SET_LAYER_DATASPACE, kSetLayerDataspaceLength);
+        writeSigned(static_cast<int32_t>(dataspace));
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerDisplayFrameLength = 4;
+    void setLayerDisplayFrame(const IComposerClient::Rect& frame) {
+        beginCommand(IComposerClient::Command::SET_LAYER_DISPLAY_FRAME,
+                     kSetLayerDisplayFrameLength);
+        writeRect(frame);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerPlaneAlphaLength = 1;
+    void setLayerPlaneAlpha(float alpha) {
+        beginCommand(IComposerClient::Command::SET_LAYER_PLANE_ALPHA, kSetLayerPlaneAlphaLength);
+        writeFloat(alpha);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerSidebandStreamLength = 1;
+    void setLayerSidebandStream(const native_handle_t* stream) {
+        beginCommand(IComposerClient::Command::SET_LAYER_SIDEBAND_STREAM,
+                     kSetLayerSidebandStreamLength);
+        writeHandle(stream);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerSourceCropLength = 4;
+    void setLayerSourceCrop(const IComposerClient::FRect& crop) {
+        beginCommand(IComposerClient::Command::SET_LAYER_SOURCE_CROP, kSetLayerSourceCropLength);
+        writeFRect(crop);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerTransformLength = 1;
+    void setLayerTransform(Transform transform) {
+        beginCommand(IComposerClient::Command::SET_LAYER_TRANSFORM, kSetLayerTransformLength);
+        writeSigned(static_cast<int32_t>(transform));
+        endCommand();
+    }
+
+    void setLayerVisibleRegion(const std::vector<IComposerClient::Rect>& visible) {
+        bool doWrite = (visible.size() <= kMaxLength / 4);
+        size_t length = (doWrite) ? visible.size() * 4 : 0;
+
+        beginCommand(IComposerClient::Command::SET_LAYER_VISIBLE_REGION, length);
+        // When there are too many rectangles in the visible region and
+        // doWrite is false, we write no rectangle at all which means the
+        // entire layer is visible.
+        if (doWrite) {
+            writeRegion(visible);
+        }
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerZOrderLength = 1;
+    void setLayerZOrder(uint32_t z) {
+        beginCommand(IComposerClient::Command::SET_LAYER_Z_ORDER, kSetLayerZOrderLength);
+        write(z);
+        endCommand();
+    }
+
+   protected:
+    void beginCommand(IComposerClient::Command command, uint16_t length) {
+        if (mCommandEnd) {
+            LOG_FATAL("endCommand was not called before command 0x%x", command);
+        }
+
+        growData(1 + length);
+        write(static_cast<uint32_t>(command) | length);
+
+        mCommandEnd = mDataWritten + length;
+    }
+
+    void endCommand() {
+        if (!mCommandEnd) {
+            LOG_FATAL("beginCommand was not called");
+        } else if (mDataWritten > mCommandEnd) {
+            LOG_FATAL("too much data written");
+            mDataWritten = mCommandEnd;
+        } else if (mDataWritten < mCommandEnd) {
+            LOG_FATAL("too little data written");
+            while (mDataWritten < mCommandEnd) {
+                write(0);
+            }
+        }
+
+        mCommandEnd = 0;
+    }
+
+    void write(uint32_t val) { mData[mDataWritten++] = val; }
+
+    void writeSigned(int32_t val) { memcpy(&mData[mDataWritten++], &val, sizeof(val)); }
+
+    void writeFloat(float val) { memcpy(&mData[mDataWritten++], &val, sizeof(val)); }
+
+    void write64(uint64_t val) {
+        uint32_t lo = static_cast<uint32_t>(val & 0xffffffff);
+        uint32_t hi = static_cast<uint32_t>(val >> 32);
+        write(lo);
+        write(hi);
+    }
+
+    void writeRect(const IComposerClient::Rect& rect) {
+        writeSigned(rect.left);
+        writeSigned(rect.top);
+        writeSigned(rect.right);
+        writeSigned(rect.bottom);
+    }
+
+    void writeRegion(const std::vector<IComposerClient::Rect>& region) {
+        for (const auto& rect : region) {
+            writeRect(rect);
+        }
+    }
+
+    void writeFRect(const IComposerClient::FRect& rect) {
+        writeFloat(rect.left);
+        writeFloat(rect.top);
+        writeFloat(rect.right);
+        writeFloat(rect.bottom);
+    }
+
+    void writeColor(const IComposerClient::Color& color) {
+        write((color.r << 0) | (color.g << 8) | (color.b << 16) | (color.a << 24));
+    }
+
+    // ownership of handle is not transferred
+    void writeHandle(const native_handle_t* handle, bool useCache) {
+        if (!handle) {
+            writeSigned(static_cast<int32_t>((useCache) ? IComposerClient::HandleIndex::CACHED
+                                                        : IComposerClient::HandleIndex::EMPTY));
+            return;
+        }
+
+        mDataHandles.push_back(handle);
+        writeSigned(mDataHandles.size() - 1);
+    }
+
+    void writeHandle(const native_handle_t* handle) { writeHandle(handle, false); }
+
+    // ownership of fence is transferred
+    void writeFence(int fence) {
+        native_handle_t* handle = nullptr;
+        if (fence >= 0) {
+            handle = getTemporaryHandle(1, 0);
+            if (handle) {
+                handle->data[0] = fence;
+            } else {
+                ALOGW("failed to get temporary handle for fence %d", fence);
+                sync_wait(fence, -1);
+                close(fence);
+            }
+        }
+
+        writeHandle(handle);
+    }
+
+    native_handle_t* getTemporaryHandle(int numFds, int numInts) {
+        native_handle_t* handle = native_handle_create(numFds, numInts);
+        if (handle) {
+            mTemporaryHandles.push_back(handle);
+        }
+        return handle;
+    }
+
+    static constexpr uint16_t kMaxLength = std::numeric_limits<uint16_t>::max();
+
+   private:
+    void growData(uint32_t grow) {
+        uint32_t newWritten = mDataWritten + grow;
+        if (newWritten < mDataWritten) {
+            LOG_ALWAYS_FATAL("buffer overflowed; data written %" PRIu32 ", growing by %" PRIu32,
+                             mDataWritten, grow);
+        }
+
+        if (newWritten <= mDataMaxSize) {
+            return;
+        }
+
+        uint32_t newMaxSize = mDataMaxSize << 1;
+        if (newMaxSize < newWritten) {
+            newMaxSize = newWritten;
+        }
+
+        auto newData = std::make_unique<uint32_t[]>(newMaxSize);
+        std::copy_n(mData.get(), mDataWritten, newData.get());
+        mDataMaxSize = newMaxSize;
+        mData = std::move(newData);
+    }
+
+    uint32_t mDataMaxSize;
+    std::unique_ptr<uint32_t[]> mData;
+
+    uint32_t mDataWritten;
+    // end offset of the current command
+    uint32_t mCommandEnd;
+
+    std::vector<hidl_handle> mDataHandles;
+    std::vector<native_handle_t*> mTemporaryHandles;
+
+    std::unique_ptr<CommandQueueType> mQueue;
+};
+
+// This class helps parse a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase {
+   public:
+    CommandReaderBase() : mDataMaxSize(0) { reset(); }
+
+    bool setMQDescriptor(const MQDescriptorSync<uint32_t>& descriptor) {
+        mQueue = std::make_unique<CommandQueueType>(descriptor, false);
+        if (mQueue->isValid()) {
+            return true;
+        } else {
+            mQueue = nullptr;
+            return false;
+        }
+    }
+
+    bool readQueue(uint32_t commandLength, const hidl_vec<hidl_handle>& commandHandles) {
+        if (!mQueue) {
+            return false;
+        }
+
+        auto quantumCount = mQueue->getQuantumCount();
+        if (mDataMaxSize < quantumCount) {
+            mDataMaxSize = quantumCount;
+            mData = std::make_unique<uint32_t[]>(mDataMaxSize);
+        }
+
+        if (commandLength > mDataMaxSize || !mQueue->read(mData.get(), commandLength)) {
+            ALOGE("failed to read commands from message queue");
+            return false;
+        }
+
+        mDataSize = commandLength;
+        mDataRead = 0;
+        mCommandBegin = 0;
+        mCommandEnd = 0;
+        mDataHandles.setToExternal(const_cast<hidl_handle*>(commandHandles.data()),
+                                   commandHandles.size());
+
+        return true;
+    }
+
+    void reset() {
+        mDataSize = 0;
+        mDataRead = 0;
+        mCommandBegin = 0;
+        mCommandEnd = 0;
+        mDataHandles.setToExternal(nullptr, 0);
+    }
+
+   protected:
+    bool isEmpty() const { return (mDataRead >= mDataSize); }
+
+    bool beginCommand(IComposerClient::Command* outCommand, uint16_t* outLength) {
+        if (mCommandEnd) {
+            LOG_FATAL("endCommand was not called for last command");
+        }
+
+        constexpr uint32_t opcode_mask =
+            static_cast<uint32_t>(IComposerClient::Command::OPCODE_MASK);
+        constexpr uint32_t length_mask =
+            static_cast<uint32_t>(IComposerClient::Command::LENGTH_MASK);
+
+        uint32_t val = read();
+        *outCommand = static_cast<IComposerClient::Command>(val & opcode_mask);
+        *outLength = static_cast<uint16_t>(val & length_mask);
+
+        if (mDataRead + *outLength > mDataSize) {
+            ALOGE("command 0x%x has invalid command length %" PRIu16, *outCommand, *outLength);
+            // undo the read() above
+            mDataRead--;
+            return false;
+        }
+
+        mCommandEnd = mDataRead + *outLength;
+
+        return true;
+    }
+
+    void endCommand() {
+        if (!mCommandEnd) {
+            LOG_FATAL("beginCommand was not called");
+        } else if (mDataRead > mCommandEnd) {
+            LOG_FATAL("too much data read");
+            mDataRead = mCommandEnd;
+        } else if (mDataRead < mCommandEnd) {
+            LOG_FATAL("too little data read");
+            mDataRead = mCommandEnd;
+        }
+
+        mCommandBegin = mCommandEnd;
+        mCommandEnd = 0;
+    }
+
+    uint32_t getCommandLoc() const { return mCommandBegin; }
+
+    uint32_t read() { return mData[mDataRead++]; }
+
+    int32_t readSigned() {
+        int32_t val;
+        memcpy(&val, &mData[mDataRead++], sizeof(val));
+        return val;
+    }
+
+    float readFloat() {
+        float val;
+        memcpy(&val, &mData[mDataRead++], sizeof(val));
+        return val;
+    }
+
+    uint64_t read64() {
+        uint32_t lo = read();
+        uint32_t hi = read();
+        return (static_cast<uint64_t>(hi) << 32) | lo;
+    }
+
+    IComposerClient::Color readColor() {
+        uint32_t val = read();
+        return IComposerClient::Color{
+            static_cast<uint8_t>((val >> 0) & 0xff), static_cast<uint8_t>((val >> 8) & 0xff),
+            static_cast<uint8_t>((val >> 16) & 0xff), static_cast<uint8_t>((val >> 24) & 0xff),
+        };
+    }
+
+    // ownership of handle is not transferred
+    const native_handle_t* readHandle(bool* outUseCache) {
+        const native_handle_t* handle = nullptr;
+
+        int32_t index = readSigned();
+        switch (index) {
+            case static_cast<int32_t>(IComposerClient::HandleIndex::EMPTY):
+                *outUseCache = false;
+                break;
+            case static_cast<int32_t>(IComposerClient::HandleIndex::CACHED):
+                *outUseCache = true;
+                break;
+            default:
+                if (static_cast<size_t>(index) < mDataHandles.size()) {
+                    handle = mDataHandles[index].getNativeHandle();
+                } else {
+                    ALOGE("invalid handle index %zu", static_cast<size_t>(index));
+                }
+                *outUseCache = false;
+                break;
+        }
+
+        return handle;
+    }
+
+    const native_handle_t* readHandle() {
+        bool useCache;
+        return readHandle(&useCache);
+    }
+
+    // ownership of fence is transferred
+    int readFence() {
+        auto handle = readHandle();
+        if (!handle || handle->numFds == 0) {
+            return -1;
+        }
+
+        if (handle->numFds != 1) {
+            ALOGE("invalid fence handle with %d fds", handle->numFds);
+            return -1;
+        }
+
+        int fd = dup(handle->data[0]);
+        if (fd < 0) {
+            ALOGW("failed to dup fence %d", handle->data[0]);
+            sync_wait(handle->data[0], -1);
+            fd = -1;
+        }
+
+        return fd;
+    }
+
+   private:
+    std::unique_ptr<CommandQueueType> mQueue;
+    uint32_t mDataMaxSize;
+    std::unique_ptr<uint32_t[]> mData;
+
+    uint32_t mDataSize;
+    uint32_t mDataRead;
+
+    // begin/end offsets of the current command
+    uint32_t mCommandBegin;
+    uint32_t mCommandEnd;
+
+    hidl_vec<hidl_handle> mDataHandles;
+};
+
+}  // namespace V2_1
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GRAPHICS_COMPOSER_COMMAND_BUFFER_H
diff --git a/graphics/composer/2.1/vts/OWNERS b/graphics/composer/2.1/vts/OWNERS
new file mode 100644
index 0000000..ef69d7c
--- /dev/null
+++ b/graphics/composer/2.1/vts/OWNERS
@@ -0,0 +1,6 @@
+# Graphics team
+olv@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
\ No newline at end of file
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 1ba7c9a..92b65a3 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -28,9 +28,11 @@
         "libsync",
     ],
     static_libs: [
-        "libhwcomposer-command-buffer",
         "VtsHalHidlTargetTestBase",
     ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
     cflags: [
         "-Wall",
         "-Wextra",
@@ -56,9 +58,11 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
         "libVtsHalGraphicsComposerTestUtils",
-        "libVtsHalGraphicsMapperTestUtils",
-        "libhwcomposer-command-buffer",
         "libnativehelper",
     ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
 }
diff --git a/graphics/composer/2.1/vts/functional/TestCommandReader.h b/graphics/composer/2.1/vts/functional/TestCommandReader.h
index 657a463..ae25d2d 100644
--- a/graphics/composer/2.1/vts/functional/TestCommandReader.h
+++ b/graphics/composer/2.1/vts/functional/TestCommandReader.h
@@ -17,7 +17,7 @@
 #ifndef TEST_COMMAND_READER_H
 #define TEST_COMMAND_READER_H
 
-#include <IComposerCommandBuffer.h>
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
 
 namespace android {
 namespace hardware {
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
index 4e69f61..00d9d8c 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerTestUtils.h
@@ -23,8 +23,8 @@
 #include <unordered_set>
 #include <vector>
 
-#include <IComposerCommandBuffer.h>
 #include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
 #include <utils/StrongPointer.h>
 
 #include "TestCommandReader.h"
@@ -58,10 +58,12 @@
   std::string dumpDebugInfo();
   std::unique_ptr<ComposerClient> createClient();
 
+ protected:
+  sp<IComposer> mComposer;
+
  private:
   void init();
 
-  sp<IComposer> mComposer;
   std::unordered_set<IComposer::Capability> mCapabilities;
 };
 
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 9a749d7..376ee37 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -17,10 +17,10 @@
 #define LOG_TAG "graphics_composer_hidl_hal_test"
 
 #include <android-base/logging.h>
+#include <mapper-vts/2.0/MapperVts.h>
 #include "GraphicsComposerCallback.h"
 #include "TestCommandReader.h"
 #include "VtsHalGraphicsComposerTestUtils.h"
-#include "VtsHalGraphicsMapperTestUtils.h"
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
@@ -48,7 +48,7 @@
 using android::hardware::graphics::common::V1_0::PixelFormat;
 using android::hardware::graphics::common::V1_0::Transform;
 using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::tests::Gralloc;
+using android::hardware::graphics::mapper::V2_0::vts::Gralloc;
 using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
 
 // Test environment for graphics.composer
diff --git a/graphics/composer/2.2/Android.bp b/graphics/composer/2.2/Android.bp
new file mode 100644
index 0000000..633a208
--- /dev/null
+++ b/graphics/composer/2.2/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.composer@2.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IComposer.hal",
+        "IComposerClient.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.composer@2.1",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
+
diff --git a/graphics/composer/2.2/IComposer.hal b/graphics/composer/2.2/IComposer.hal
new file mode 100644
index 0000000..05052c8
--- /dev/null
+++ b/graphics/composer/2.2/IComposer.hal
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer@2.2;
+
+import @2.1::IComposer;
+
+interface IComposer extends @2.1::IComposer {
+
+    /* createClient from @2.1::IComposer must return an instance of @2.2::IComposerClient */
+
+};
diff --git a/graphics/composer/2.2/IComposerClient.hal b/graphics/composer/2.2/IComposerClient.hal
new file mode 100644
index 0000000..dcd9c8d
--- /dev/null
+++ b/graphics/composer/2.2/IComposerClient.hal
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer@2.2;
+
+import android.hardware.graphics.common@1.0::PixelFormat;
+import android.hardware.graphics.common@1.0::Dataspace;
+import @2.1::IComposerClient;
+import @2.1::Display;
+import @2.1::Error;
+
+interface IComposerClient extends @2.1::IComposerClient {
+
+    enum PowerMode : @2.1::IComposerClient.PowerMode {
+        /**
+         * The display is configured as in ON but may stop applying display
+         * updates from the client. This is effectively a hint to the device
+         * that drawing to the display has been suspended and that the the
+         * device must remain on and continue displaying its current contents
+         * indefinitely until the power mode changes.
+         *
+         * This mode may also be used as a signal to enable hardware-based
+         * functionality to take over the display and manage it autonomously
+         * to implement a low power always-on display.
+         */
+        ON_SUSPEND = 4
+    };
+
+    /**
+     * Following enums define keys for metadata defined by SMPTE ST 2086:2014
+     * and CTA 861.3.
+     */
+    enum PerFrameMetadataKey : int32_t {
+        /** SMPTE ST 2084:2014.
+         * Coordinates defined in CIE 1931 xy chromaticity space
+         */
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_RED_PRIMARY_X,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_RED_PRIMARY_Y,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_GREEN_PRIMARY_X,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_GREEN_PRIMARY_Y,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_BLUE_PRIMARY_X,
+        /** SMPTE ST 2084:2014 */
+        DISPLAY_BLUE_PRIMARY_Y,
+        /** SMPTE ST 2084:2014 */
+        WHITE_POINT_X,
+        /** SMPTE ST 2084:2014 */
+        WHITE_POINT_Y,
+        /** SMPTE ST 2084:2014.
+         * Units: nits
+         * max as defined by ST 2048: 10,000 nits
+         */
+        MAX_LUMINANCE,
+        /** SMPTE ST 2084:2014 */
+        MIN_LUMINANCE,
+        /** CTA 861.3 */
+        MAX_CONTENT_LIGHT_LEVEL,
+        /** CTA 861.3 */
+        MAX_FRAME_AVERAGE_LIGHT_LEVEL,
+    };
+
+    struct PerFrameMetadata {
+        PerFrameMetadataKey key;
+        float value;
+    };
+
+    struct FloatColor {
+        float r;
+        float g;
+        float b;
+        float a;
+    };
+
+    enum Command : @2.1::IComposerClient.Command {
+        /**
+         * setPerFrameMetadata(Display display, vec<PerFrameMetadata> data)
+         * Sets the PerFrameMetadata for the display. This metadata must be used
+         * by the implementation to better tone map content to that display.
+         *
+         * This is a method that may be called every frame. Thus it's
+         * implemented using buffered transport.
+         * SET_PER_FRAME_METADATA is the command used by the buffered transport
+         * mechanism.
+         */
+        SET_PER_FRAME_METADATA = 0x207 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+
+        /**
+         * SET_LAYER_COLOR has this pseudo prototype
+         *
+         *   setLayerColor(FloatColor color);
+         *
+         * Sets the color of the given layer. If the composition type of the layer
+         * is not Composition::SOLID_COLOR, this call must succeed and have no
+         * other effect.
+         *
+         * @param color is the new color using float type.
+         */
+        SET_LAYER_FLOAT_COLOR = 0x40c << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+    };
+
+    /**
+     * Returns the PerFrameMetadataKeys that are supported by this device.
+     *
+     * @param display is the display on which to create the layer.
+     * @return keys is the vector of PerFrameMetadataKey keys that are
+     *        supported by this device.
+     * @return error is NONE upon success. Otherwise,
+     *         UNSUPPORTED if not supported on underlying HAL
+     */
+    getPerFrameMetadataKeys(Display display)
+        generates (Error error,
+                   vec<PerFrameMetadataKey> keys);
+
+    /**
+     * getReadbackBufferAttributes
+     * Returns the format which should be used when allocating a buffer for use by
+     * device readback as well as the dataspace in which its contents should be
+     * interpreted.
+     *
+     * The width and height of this buffer must be those of the currently-active
+     * display configuration, and the usage flags must consist of the following:
+     *   BufferUsage::CPU_READ | BufferUsage::GPU_TEXTURE |
+     *   BufferUsage::COMPOSER_OUTPUT
+     *
+     * The format and dataspace provided must be sufficient such that if a
+     * correctly-configured buffer is passed into setReadbackBuffer, filled by
+     * the device, and then displayed by the client as a full-screen buffer, the
+     * output of the display remains the same (subject to the note about protected
+     * content in the description of setReadbackBuffer).
+     *
+     * Parameters:
+     * @param display - the display on which to create the layer.
+     *
+     * @return format - the format the client should use when allocating a device
+     *       readback buffer
+     * @return dataspace - the dataspace to use when interpreting the
+     *       contents of a device readback buffer
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         UNSUPPORTED if not supported on underlying HAL
+     *
+     * See also:
+     *   setReadbackBuffer
+     *   getReadbackBufferFence
+     */
+    getReadbackBufferAttributes(Display display)
+        generates (Error error,
+                   PixelFormat format,
+                   Dataspace dataspace);
+
+    /**
+     * getReadbackBufferFence
+     * Returns an acquire sync fence file descriptor which must signal when the
+     * buffer provided to setReadbackBuffer has been filled by the device and is
+     * safe for the client to read.
+     *
+     * If it is already safe to read from this buffer, -1 may be returned instead.
+     * The client takes ownership of this file descriptor and is responsible for
+     * closing it when it is no longer needed.
+     *
+     * This function must be called immediately after the composition cycle being
+     * captured into the readback buffer. The complete ordering of a readback buffer
+     * capture is as follows:
+     *
+     *   getReadbackBufferAttributes
+     *   // Readback buffer is allocated
+     *   // Many frames may pass
+     *
+     *   setReadbackBuffer
+     *   validateDisplay
+     *   presentDisplay
+     *   getReadbackBufferFence
+     *   // Implicitly wait on the acquire fence before accessing the buffer
+     *
+     * Parameters:
+     * @param display - the display on which to create the layer.
+     *
+     * @return acquireFence - a sync fence file descriptor as described above; pointer
+     *       must be non-NULL
+     * @return error - is HWC2_ERROR_NONE or one of the following errors:
+     *         BAD_DISPLAY - an invalid display handle was passed in
+     *         UNSUPPORTED if not supported on underlying HAL
+     *
+     * See also:
+     *   getReadbackBufferAttributes
+     *   setReadbackBuffer
+     */
+    getReadbackBufferFence(Display display)
+                generates (Error error,
+                           handle acquireFence);
+
+    /**
+     * setReadbackBuffer
+     * Sets the readback buffer to be filled with the contents of the next
+     * composition performed for this display (i.e., the contents present at the
+     * time of the next validateDisplay/presentDisplay cycle).
+     *
+     * This buffer must have been allocated as described in
+     * getReadbackBufferAttributes and is in the dataspace provided by the same.
+     *
+     * If there is hardware protected content on the display at the time of the next
+     * composition, the area of the readback buffer covered by such content must be
+     * completely black. Any areas of the buffer not covered by such content may
+     * optionally be black as well.
+     *
+     * The release fence file descriptor provided works identically to the one
+     * described for setOutputBuffer.
+     *
+     * This function must not be called between any call to validateDisplay and a
+     * subsequent call to presentDisplay.
+     *
+     * Parameters:
+     * @param display - the display on which to create the layer.
+     * @param buffer - the new readback buffer
+     * @param releaseFence - a sync fence file descriptor as described in setOutputBuffer
+     *
+     * @return error - is HWC2_ERROR_NONE or one of the following errors:
+     *   HWC2_ERROR_BAD_DISPLAY - an invalid display handle was passed in
+     *   HWC2_ERROR_BAD_PARAMETER - the new readback buffer handle was invalid
+     *
+     * See also:
+     *   getReadbackBufferAttributes
+     *   getReadbackBufferFence
+     */
+    setReadbackBuffer(Display display, handle buffer, handle releaseFence) generates (Error error);
+
+    /**
+     * setPowerMode_2_2
+     * Sets the power mode of the given display. The transition must be
+     * complete when this function returns. It is valid to call this function
+     * multiple times with the same power mode.
+     *
+     * All displays must support PowerMode::ON and PowerMode::OFF.  Whether a
+     * display supports PowerMode::DOZE or PowerMode::DOZE_SUSPEND may be
+     * queried using getDozeSupport.
+     *
+     * @param display is the display to which the power mode is set.
+     * @param mode is the new power mode.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         BAD_PARAMETER when mode was not a valid power mode.
+     *         UNSUPPORTED when mode is not supported on this display.
+     */
+    setPowerMode_2_2(Display display, PowerMode mode) generates (Error error);
+
+};
diff --git a/graphics/composer/2.2/utils/OWNERS b/graphics/composer/2.2/utils/OWNERS
new file mode 100644
index 0000000..1beb074
--- /dev/null
+++ b/graphics/composer/2.2/utils/OWNERS
@@ -0,0 +1,8 @@
+# Graphics team
+courtneygo@google.com
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.2/utils/command-buffer/Android.bp b/graphics/composer/2.2/utils/command-buffer/Android.bp
new file mode 100644
index 0000000..efaabd4
--- /dev/null
+++ b/graphics/composer/2.2/utils/command-buffer/Android.bp
@@ -0,0 +1,13 @@
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.2-command-buffer",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
new file mode 100644
index 0000000..c803d3c
--- /dev/null
+++ b/graphics/composer/2.2/utils/command-buffer/include/composer-command-buffer/2.2/ComposerCommandBuffer.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <fmq/MessageQueue.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+
+using android::hardware::MessageQueue;
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::composer::V2_1::Config;
+using android::hardware::graphics::composer::V2_1::Display;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_1::IComposerCallback;
+using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+
+using CommandQueueType = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+// This class helps build a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase : public V2_1::CommandWriterBase {
+   public:
+    CommandWriterBase(uint32_t initialMaxSize) : V2_1::CommandWriterBase(initialMaxSize) {}
+
+    static constexpr uint16_t kSetLayerFloatColorLength = 4;
+    void setLayerFloatColor(IComposerClient::FloatColor color) {
+        beginCommand_2_2(IComposerClient::Command::SET_LAYER_FLOAT_COLOR,
+                         kSetLayerFloatColorLength);
+        writeFloatColor(color);
+        endCommand();
+    }
+
+    void setPerFrameMetadata(const hidl_vec<IComposerClient::PerFrameMetadata>& metadataVec) {
+        beginCommand_2_2(IComposerClient::Command::SET_PER_FRAME_METADATA, metadataVec.size() * 2);
+        for (const auto& metadata : metadataVec) {
+            writeSigned(static_cast<int32_t>(metadata.key));
+            writeFloat(metadata.value);
+        }
+        endCommand();
+    }
+
+   protected:
+    void beginCommand_2_2(IComposerClient::Command command, uint16_t length) {
+        V2_1::CommandWriterBase::beginCommand(
+            static_cast<V2_1::IComposerClient::Command>(static_cast<int32_t>(command)), length);
+    }
+
+    void writeFloatColor(const IComposerClient::FloatColor& color) {
+        writeFloat(color.r);
+        writeFloat(color.g);
+        writeFloat(color.b);
+        writeFloat(color.a);
+    }
+};
+
+// This class helps parse a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase : public V2_1::CommandReaderBase {
+   public:
+    CommandReaderBase() : V2_1::CommandReaderBase(){};
+
+   protected:
+    IComposerClient::FloatColor readFloatColor() {
+        float r = readFloat();
+        float g = readFloat();
+        float b = readFloat();
+        float a = readFloat();
+        return IComposerClient::FloatColor{r, g, b, a};
+    }
+};
+
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
new file mode 100644
index 0000000..78322a1
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -0,0 +1,74 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "libVtsHalGraphicsComposerTestUtils@2.2",
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "VtsHalGraphicsComposerTestUtils.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "libfmq",
+        "libsync",
+    ],
+    static_libs: [
+        "libVtsHalGraphicsComposerTestUtils",
+        "VtsHalHidlTargetTestBase",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-O0",
+        "-g",
+        "-DLOG_TAG=\"GraphicsComposerTestUtils@2.2\"",
+    ],
+    export_include_dirs: ["include"],
+}
+
+cc_test {
+    name: "VtsHalGraphicsComposerV2_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalGraphicsComposerV2_2TargetTest.cpp"],
+
+    // TODO(b/64437680): Assume these libs are always available on the device.
+    shared_libs: [
+        "libfmq",
+	"libhidltransport",
+        "libsync",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1",
+        "libVtsHalGraphicsComposerTestUtils",
+        "libVtsHalGraphicsComposerTestUtils@2.2",
+        "libnativehelper",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+}
diff --git a/graphics/composer/2.2/vts/functional/OWNERS b/graphics/composer/2.2/vts/functional/OWNERS
new file mode 100644
index 0000000..1beb074
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/OWNERS
@@ -0,0 +1,8 @@
+# Graphics team
+courtneygo@google.com
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
new file mode 100644
index 0000000..00946ce
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerTestUtils.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <hidl/HidlTransportUtils.h>
+
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include "2.2/VtsHalGraphicsComposerTestUtils.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace tests {
+
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+using android::hardware::details::getDescriptor;
+using android::hardware::details::canCastInterface;
+
+std::unique_ptr<ComposerClient_v2_2> Composer_v2_2::createClient_v2_2() {
+    std::unique_ptr<ComposerClient_v2_2> client;
+    mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+        ALOGV("tmpClient is a %s", getDescriptor(&(*tmpClient)).c_str());
+        ASSERT_TRUE(canCastInterface(
+            &(*tmpClient), "android.hardware.graphics.composer@2.2::IComposerClient", false))
+            << "Cannot create 2.2 IComposerClient";
+        client = std::make_unique<ComposerClient_v2_2>(IComposerClient::castFrom(tmpClient, true));
+    });
+
+    return client;
+}
+
+std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient_v2_2::getPerFrameMetadataKeys(
+    Display display) {
+    std::vector<IComposerClient::PerFrameMetadataKey> keys;
+    mClient_v2_2->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR metadata keys";
+        keys = tmpKeys;
+    });
+
+    return keys;
+}
+
+void ComposerClient_v2_2::execute_v2_2(V2_1::tests::TestCommandReader* reader,
+                                       V2_2::CommandWriterBase* writer) {
+    bool queueChanged = false;
+    uint32_t commandLength = 0;
+    hidl_vec<hidl_handle> commandHandles;
+    ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
+
+    if (queueChanged) {
+        auto ret = mClient_v2_2->setInputCommandQueue(*writer->getMQDescriptor());
+        ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
+        return;
+    }
+
+    mClient_v2_2->executeCommands(commandLength, commandHandles,
+                                  [&](const auto& tmpError, const auto& tmpOutQueueChanged,
+                                      const auto& tmpOutLength, const auto& tmpOutHandles) {
+                                      ASSERT_EQ(Error::NONE, tmpError);
+
+                                      if (tmpOutQueueChanged) {
+                                          mClient_v2_2->getOutputCommandQueue(
+                                              [&](const auto& tmpError, const auto& tmpDescriptor) {
+                                                  ASSERT_EQ(Error::NONE, tmpError);
+                                                  reader->setMQDescriptor(tmpDescriptor);
+                                              });
+                                      }
+
+                                      ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
+                                      reader->parse();
+                                  });
+}
+
+void ComposerClient_v2_2::setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode) {
+    Error error = mClient_v2_2->setPowerMode_2_2(display, mode);
+    ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set power mode";
+}
+
+void ComposerClient_v2_2::setReadbackBuffer(Display display, const native_handle_t* buffer,
+                                            int32_t /* releaseFence */) {
+    // Ignoring fence, HIDL doesn't care
+    Error error = mClient_v2_2->setReadbackBuffer(display, buffer, nullptr);
+    ASSERT_EQ(Error::NONE, error) << "failed to setReadbackBuffer";
+}
+
+void ComposerClient_v2_2::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                                      Dataspace* outDataspace) {
+    mClient_v2_2->getReadbackBufferAttributes(
+        display,
+        [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) {
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback buffer attributes";
+            *outPixelFormat = tmpOutPixelFormat;
+            *outDataspace = tmpOutDataspace;
+        });
+}
+
+void ComposerClient_v2_2::getReadbackBufferFence(Display display, int32_t* outFence) {
+    hidl_handle handle;
+    mClient_v2_2->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback fence";
+        handle = tmpHandle;
+    });
+    *outFence = 0;
+}
+
+}  // namespace tests
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
new file mode 100644
index 0000000..6fbdd3c
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "graphics_composer_hidl_hal_test@2.2"
+
+#include <android-base/logging.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <mapper-vts/2.0/MapperVts.h>
+#include <sync/sync.h>
+#include "2.2/VtsHalGraphicsComposerTestUtils.h"
+#include "GraphicsComposerCallback.h"
+#include "TestCommandReader.h"
+#include "VtsHalGraphicsComposerTestUtils.h"
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace tests {
+namespace {
+
+using android::hardware::graphics::common::V1_0::BufferUsage;
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::ColorTransform;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::common::V1_0::Transform;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+using android::hardware::graphics::mapper::V2_0::IMapper;
+using android::hardware::graphics::mapper::V2_0::vts::Gralloc;
+using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
+
+// Test environment for graphics.composer
+class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static GraphicsComposerHidlEnvironment* Instance() {
+        static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IComposer>(); }
+
+   private:
+    GraphicsComposerHidlEnvironment() {}
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
+};
+
+class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(
+            mComposer = std::make_unique<Composer_v2_2>(
+                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient_v2_2());
+
+        mComposerCallback = new V2_1::tests::GraphicsComposerCallback;
+        mComposerClient->registerCallback(mComposerCallback);
+
+        // assume the first display is primary and is never removed
+        mPrimaryDisplay = waitForFirstDisplay();
+
+        // explicitly disable vsync
+        mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+        mComposerCallback->setVsyncAllowed(false);
+    }
+
+    void TearDown() override {
+        if (mComposerCallback != nullptr) {
+            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+        }
+    }
+
+    // use the slot count usually set by SF
+    static constexpr uint32_t kBufferSlotCount = 64;
+
+    std::unique_ptr<Composer_v2_2> mComposer;
+    std::unique_ptr<ComposerClient_v2_2> mComposerClient;
+    sp<V2_1::tests::GraphicsComposerCallback> mComposerCallback;
+    // the first display and is assumed never to be removed
+    Display mPrimaryDisplay;
+
+   private:
+    Display waitForFirstDisplay() {
+        while (true) {
+            std::vector<Display> displays = mComposerCallback->getDisplays();
+            if (displays.empty()) {
+                usleep(5 * 1000);
+                continue;
+            }
+
+            return displays[0];
+        }
+    }
+};
+
+// Tests for IComposerClient::Command.
+class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
+   protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
+
+        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+
+        mWriter = std::make_unique<V2_2::CommandWriterBase>(1024);
+        mReader = std::make_unique<V2_1::tests::TestCommandReader>();
+    }
+
+    void TearDown() override { ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); }
+
+    const native_handle_t* allocate() {
+        IMapper::BufferDescriptorInfo info{};
+        info.width = 64;
+        info.height = 64;
+        info.layerCount = 1;
+        info.format = PixelFormat::RGBA_8888;
+        info.usage =
+            static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+        return mGralloc->allocate(info);
+    }
+
+    void execute() { mComposerClient->execute_v2_2(mReader.get(), mWriter.get()); }
+
+    std::unique_ptr<V2_2::CommandWriterBase> mWriter;
+    std::unique_ptr<V2_1::tests::TestCommandReader> mReader;
+
+   private:
+    std::unique_ptr<Gralloc> mGralloc;
+};
+
+/**
+ * Test IComposerClient::Command::SET_PER_FRAME_METADATA.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_PER_FRAME_METADATA) {
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+
+    /**
+     * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
+     * the D65 white point and the SRGB transfer functions.
+     * Rendering Intent: Colorimetric
+     * Primaries:
+     *                  x       y
+     *  green           0.265   0.690
+     *  blue            0.150   0.060
+     *  red             0.680   0.320
+     *  white (D65)     0.3127  0.3290
+     */
+
+    std::vector<IComposerClient::PerFrameMetadata> hidlMetadata;
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X, 0.265});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y, 0.690});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X, 0.150});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y, 0.060});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_X, 0.3127});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::WHITE_POINT_Y, 0.3290});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_LUMINANCE, 100.0});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MIN_LUMINANCE, 0.1});
+    hidlMetadata.push_back({IComposerClient::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0});
+    hidlMetadata.push_back(
+        {IComposerClient::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
+    mWriter->setPerFrameMetadata(hidlMetadata);
+    execute();
+}
+
+/**
+ * Test IComposerClient::getPerFrameMetadataKeys.
+ */
+TEST_F(GraphicsComposerHidlTest, GetPerFrameMetadataKeys) {
+    mComposerClient->getPerFrameMetadataKeys(mPrimaryDisplay);
+}
+/**
+ * Test IComposerClient::setPowerMode_2_2.
+ */
+TEST_F(GraphicsComposerHidlTest, setPowerMode_2_2) {
+    std::vector<IComposerClient::PowerMode> modes;
+    modes.push_back(IComposerClient::PowerMode::OFF);
+    modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);
+    modes.push_back(IComposerClient::PowerMode::ON);
+
+    for (auto mode : modes) {
+        mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode);
+    }
+}
+
+TEST_F(GraphicsComposerHidlTest, setReadbackBuffer) {
+    mComposerClient->setReadbackBuffer(mPrimaryDisplay, nullptr, -1);
+}
+
+TEST_F(GraphicsComposerHidlTest, getReadbackBufferFence) {
+    int32_t fence;
+    mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence);
+}
+
+TEST_F(GraphicsComposerHidlTest, getReadbackBufferAttributes) {
+    PixelFormat pixelFormat;
+    Dataspace dataspace;
+    mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat, &dataspace);
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_FLOAT_COLOR.
+ */
+TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_FLOAT_COLOR) {
+    V2_1::Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+    mWriter->setLayerFloatColor(IComposerClient::FloatColor{1.0, 1.0, 1.0, 1.0});
+    mWriter->setLayerFloatColor(IComposerClient::FloatColor{0.0, 0.0, 0.0, 0.0});
+}
+
+}  // namespace
+}  // namespace tests
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    using android::hardware::graphics::composer::V2_2::tests::GraphicsComposerHidlEnvironment;
+    ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    return status;
+}
diff --git a/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h b/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h
new file mode 100644
index 0000000..c5756ed
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/include/2.2/VtsHalGraphicsComposerTestUtils.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include <VtsHalGraphicsComposerTestUtils.h>
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/graphics/composer/2.2/IComposer.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace tests {
+
+using android::hardware::graphics::common::V1_0::ColorMode;
+using android::hardware::graphics::common::V1_0::Dataspace;
+using android::hardware::graphics::common::V1_0::Hdr;
+using android::hardware::graphics::common::V1_0::PixelFormat;
+using android::hardware::graphics::composer::V2_2::IComposer;
+using android::hardware::graphics::composer::V2_2::IComposerClient;
+
+class ComposerClient_v2_2;
+
+// Only thing I need for Composer_v2_2 is to create a v2_2 ComposerClient
+// Everything else is the same
+class Composer_v2_2 : public V2_1::tests::Composer {
+   public:
+    Composer_v2_2() : V2_1::tests::Composer(){};
+    explicit Composer_v2_2(const std::string& name) : V2_1::tests::Composer(name){};
+
+    std::unique_ptr<ComposerClient_v2_2> createClient_v2_2();
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient_v2_2
+    : public android::hardware::graphics::composer::V2_1::tests::ComposerClient {
+   public:
+    ComposerClient_v2_2(const sp<IComposerClient>& client)
+        : V2_1::tests::ComposerClient(client), mClient_v2_2(client){};
+
+    void execute_v2_2(V2_1::tests::TestCommandReader* reader, V2_2::CommandWriterBase* writer);
+
+    std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(Display display);
+
+    void setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode);
+    void setReadbackBuffer(Display display, const native_handle_t* buffer, int32_t releaseFence);
+    void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                     Dataspace* outDataspace);
+    void getReadbackBufferFence(Display display, int32_t* outFence);
+
+   private:
+    sp<V2_2::IComposerClient> mClient_v2_2;
+};
+
+}  // namespace tests
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/utils/vts/Android.bp b/graphics/mapper/2.0/utils/vts/Android.bp
index 8bca152..1aa3185 100644
--- a/graphics/mapper/2.0/utils/vts/Android.bp
+++ b/graphics/mapper/2.0/utils/vts/Android.bp
@@ -15,9 +15,9 @@
 //
 
 cc_library_static {
-    name: "libVtsHalGraphicsMapperTestUtils",
+    name: "android.hardware.graphics.mapper@2.0-vts",
     defaults: ["hidl_defaults"],
-    srcs: ["VtsHalGraphicsMapperTestUtils.cpp"],
+    srcs: ["MapperVts.cpp"],
     cflags: [
         "-O0",
         "-g",
@@ -34,5 +34,5 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
     ],
-    export_include_dirs: ["."],
+    export_include_dirs: ["include"],
 }
diff --git a/graphics/mapper/2.0/utils/vts/MapperVts.cpp b/graphics/mapper/2.0/utils/vts/MapperVts.cpp
new file mode 100644
index 0000000..d08ac56
--- /dev/null
+++ b/graphics/mapper/2.0/utils/vts/MapperVts.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mapper-vts/2.0/MapperVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace vts {
+
+Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
+    init(allocatorServiceName, mapperServiceName);
+}
+
+void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
+    mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+    ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+
+    mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+    ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
+    ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+}
+
+Gralloc::~Gralloc() {
+    for (auto bufferHandle : mClonedBuffers) {
+        auto buffer = const_cast<native_handle_t*>(bufferHandle);
+        native_handle_close(buffer);
+        native_handle_delete(buffer);
+    }
+    mClonedBuffers.clear();
+
+    for (auto bufferHandle : mImportedBuffers) {
+        auto buffer = const_cast<native_handle_t*>(bufferHandle);
+        EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer)) << "failed to free buffer " << buffer;
+    }
+    mImportedBuffers.clear();
+}
+
+sp<IAllocator> Gralloc::getAllocator() const {
+    return mAllocator;
+}
+
+std::string Gralloc::dumpDebugInfo() {
+    std::string debugInfo;
+    mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+    return debugInfo;
+}
+
+const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) {
+    const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
+    EXPECT_NE(nullptr, bufferHandle);
+
+    if (bufferHandle) {
+        mClonedBuffers.insert(bufferHandle);
+    }
+
+    return bufferHandle;
+}
+
+std::vector<const native_handle_t*> Gralloc::allocate(const BufferDescriptor& descriptor,
+                                                      uint32_t count, bool import,
+                                                      uint32_t* outStride) {
+    std::vector<const native_handle_t*> bufferHandles;
+    bufferHandles.reserve(count);
+    mAllocator->allocate(
+        descriptor, count,
+        [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
+            ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
+
+            for (uint32_t i = 0; i < count; i++) {
+                if (import) {
+                    ASSERT_NO_FATAL_FAILURE(bufferHandles.push_back(importBuffer(tmpBuffers[i])));
+                } else {
+                    ASSERT_NO_FATAL_FAILURE(bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
+                }
+            }
+
+            if (outStride) {
+                *outStride = tmpStride;
+            }
+        });
+
+    if (::testing::Test::HasFatalFailure()) {
+        bufferHandles.clear();
+    }
+
+    return bufferHandles;
+}
+
+const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                         bool import, uint32_t* outStride) {
+    BufferDescriptor descriptor = createDescriptor(descriptorInfo);
+    if (::testing::Test::HasFatalFailure()) {
+        return nullptr;
+    }
+
+    auto buffers = allocate(descriptor, 1, import, outStride);
+    if (::testing::Test::HasFatalFailure()) {
+        return nullptr;
+    }
+
+    return buffers[0];
+}
+
+sp<IMapper> Gralloc::getMapper() const {
+    return mMapper;
+}
+
+BufferDescriptor Gralloc::createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+    BufferDescriptor descriptor;
+    mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
+        descriptor = tmpDescriptor;
+    });
+
+    return descriptor;
+}
+
+const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle) {
+    const native_handle_t* bufferHandle = nullptr;
+    mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+        ASSERT_EQ(Error::NONE, tmpError)
+            << "failed to import buffer %p" << rawHandle.getNativeHandle();
+        bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
+    });
+
+    if (bufferHandle) {
+        mImportedBuffers.insert(bufferHandle);
+    }
+
+    return bufferHandle;
+}
+
+void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    if (mImportedBuffers.erase(bufferHandle)) {
+        Error error = mMapper->freeBuffer(buffer);
+        ASSERT_EQ(Error::NONE, error) << "failed to free buffer " << buffer;
+    } else {
+        mClonedBuffers.erase(bufferHandle);
+        native_handle_close(buffer);
+        native_handle_delete(buffer);
+    }
+}
+
+void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                    const IMapper::Rect& accessRegion, int acquireFence) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+    hidl_handle acquireFenceHandle;
+    if (acquireFence >= 0) {
+        auto h = native_handle_init(acquireFenceStorage, 1, 0);
+        h->data[0] = acquireFence;
+        acquireFenceHandle = h;
+    }
+
+    void* data = nullptr;
+    mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+                  [&](const auto& tmpError, const auto& tmpData) {
+                      ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer;
+                      data = tmpData;
+                  });
+
+    if (acquireFence >= 0) {
+        close(acquireFence);
+    }
+
+    return data;
+}
+
+YCbCrLayout Gralloc::lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                               const IMapper::Rect& accessRegion, int acquireFence) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+    hidl_handle acquireFenceHandle;
+    if (acquireFence >= 0) {
+        auto h = native_handle_init(acquireFenceStorage, 1, 0);
+        h->data[0] = acquireFence;
+        acquireFenceHandle = h;
+    }
+
+    YCbCrLayout layout = {};
+    mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+                       [&](const auto& tmpError, const auto& tmpLayout) {
+                           ASSERT_EQ(Error::NONE, tmpError)
+                               << "failed to lockYCbCr buffer " << buffer;
+                           layout = tmpLayout;
+                       });
+
+    if (acquireFence >= 0) {
+        close(acquireFence);
+    }
+
+    return layout;
+}
+
+int Gralloc::unlock(const native_handle_t* bufferHandle) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    int releaseFence = -1;
+    mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock buffer " << buffer;
+
+        auto fenceHandle = tmpReleaseFence.getNativeHandle();
+        if (fenceHandle) {
+            ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle " << fenceHandle;
+            if (fenceHandle->numFds == 1) {
+                releaseFence = dup(fenceHandle->data[0]);
+                ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
+            } else {
+                ASSERT_EQ(0, fenceHandle->numFds) << " invalid fence handle " << fenceHandle;
+            }
+        }
+    });
+
+    return releaseFence;
+}
+
+}  // namespace vts
+}  // namespace V2_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/utils/vts/VtsHalGraphicsMapperTestUtils.cpp b/graphics/mapper/2.0/utils/vts/VtsHalGraphicsMapperTestUtils.cpp
deleted file mode 100644
index e3229ca..0000000
--- a/graphics/mapper/2.0/utils/vts/VtsHalGraphicsMapperTestUtils.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <VtsHalHidlTargetTestBase.h>
-
-#include "VtsHalGraphicsMapperTestUtils.h"
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace mapper {
-namespace V2_0 {
-namespace tests {
-
-Gralloc::Gralloc() {
-    init();
-}
-
-void Gralloc::init() {
-    mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(
-        GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>());
-    ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
-
-    mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(
-        GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>());
-    ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
-    ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
-}
-
-Gralloc::~Gralloc() {
-    for (auto bufferHandle : mClonedBuffers) {
-        auto buffer = const_cast<native_handle_t*>(bufferHandle);
-        native_handle_close(buffer);
-        native_handle_delete(buffer);
-    }
-    mClonedBuffers.clear();
-
-    for (auto bufferHandle : mImportedBuffers) {
-        auto buffer = const_cast<native_handle_t*>(bufferHandle);
-        EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer)) << "failed to free buffer " << buffer;
-    }
-    mImportedBuffers.clear();
-}
-
-sp<IAllocator> Gralloc::getAllocator() const {
-    return mAllocator;
-}
-
-std::string Gralloc::dumpDebugInfo() {
-    std::string debugInfo;
-    mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
-
-    return debugInfo;
-}
-
-const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) {
-    const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
-    EXPECT_NE(nullptr, bufferHandle);
-
-    if (bufferHandle) {
-        mClonedBuffers.insert(bufferHandle);
-    }
-
-    return bufferHandle;
-}
-
-std::vector<const native_handle_t*> Gralloc::allocate(const BufferDescriptor& descriptor,
-                                                      uint32_t count, bool import,
-                                                      uint32_t* outStride) {
-    std::vector<const native_handle_t*> bufferHandles;
-    bufferHandles.reserve(count);
-    mAllocator->allocate(
-        descriptor, count,
-        [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
-            ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
-            ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
-
-            for (uint32_t i = 0; i < count; i++) {
-                if (import) {
-                    ASSERT_NO_FATAL_FAILURE(bufferHandles.push_back(importBuffer(tmpBuffers[i])));
-                } else {
-                    ASSERT_NO_FATAL_FAILURE(bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
-                }
-            }
-
-            if (outStride) {
-                *outStride = tmpStride;
-            }
-        });
-
-    if (::testing::Test::HasFatalFailure()) {
-        bufferHandles.clear();
-    }
-
-    return bufferHandles;
-}
-
-const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
-                                         bool import, uint32_t* outStride) {
-    BufferDescriptor descriptor = createDescriptor(descriptorInfo);
-    if (::testing::Test::HasFatalFailure()) {
-        return nullptr;
-    }
-
-    auto buffers = allocate(descriptor, 1, import, outStride);
-    if (::testing::Test::HasFatalFailure()) {
-        return nullptr;
-    }
-
-    return buffers[0];
-}
-
-sp<IMapper> Gralloc::getMapper() const {
-    return mMapper;
-}
-
-BufferDescriptor Gralloc::createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
-    BufferDescriptor descriptor;
-    mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
-        ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
-        descriptor = tmpDescriptor;
-    });
-
-    return descriptor;
-}
-
-const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle) {
-    const native_handle_t* bufferHandle = nullptr;
-    mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
-        ASSERT_EQ(Error::NONE, tmpError)
-            << "failed to import buffer %p" << rawHandle.getNativeHandle();
-        bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
-    });
-
-    if (bufferHandle) {
-        mImportedBuffers.insert(bufferHandle);
-    }
-
-    return bufferHandle;
-}
-
-void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    if (mImportedBuffers.erase(bufferHandle)) {
-        Error error = mMapper->freeBuffer(buffer);
-        ASSERT_EQ(Error::NONE, error) << "failed to free buffer " << buffer;
-    } else {
-        mClonedBuffers.erase(bufferHandle);
-        native_handle_close(buffer);
-        native_handle_delete(buffer);
-    }
-}
-
-void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-                    const IMapper::Rect& accessRegion, int acquireFence) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
-    hidl_handle acquireFenceHandle;
-    if (acquireFence >= 0) {
-        auto h = native_handle_init(acquireFenceStorage, 1, 0);
-        h->data[0] = acquireFence;
-        acquireFenceHandle = h;
-    }
-
-    void* data = nullptr;
-    mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                  [&](const auto& tmpError, const auto& tmpData) {
-                      ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer;
-                      data = tmpData;
-                  });
-
-    if (acquireFence >= 0) {
-        close(acquireFence);
-    }
-
-    return data;
-}
-
-YCbCrLayout Gralloc::lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-                               const IMapper::Rect& accessRegion, int acquireFence) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
-    hidl_handle acquireFenceHandle;
-    if (acquireFence >= 0) {
-        auto h = native_handle_init(acquireFenceStorage, 1, 0);
-        h->data[0] = acquireFence;
-        acquireFenceHandle = h;
-    }
-
-    YCbCrLayout layout = {};
-    mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                       [&](const auto& tmpError, const auto& tmpLayout) {
-                           ASSERT_EQ(Error::NONE, tmpError)
-                               << "failed to lockYCbCr buffer " << buffer;
-                           layout = tmpLayout;
-                       });
-
-    if (acquireFence >= 0) {
-        close(acquireFence);
-    }
-
-    return layout;
-}
-
-int Gralloc::unlock(const native_handle_t* bufferHandle) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    int releaseFence = -1;
-    mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
-        ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock buffer " << buffer;
-
-        auto fenceHandle = tmpReleaseFence.getNativeHandle();
-        if (fenceHandle) {
-            ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle " << fenceHandle;
-            if (fenceHandle->numFds == 1) {
-                releaseFence = dup(fenceHandle->data[0]);
-                ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
-            } else {
-                ASSERT_EQ(0, fenceHandle->numFds) << " invalid fence handle " << fenceHandle;
-            }
-        }
-    });
-
-    return releaseFence;
-}
-
-}  // namespace tests
-}  // namespace V2_0
-}  // namespace mapper
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/mapper/2.0/utils/vts/VtsHalGraphicsMapperTestUtils.h b/graphics/mapper/2.0/utils/vts/VtsHalGraphicsMapperTestUtils.h
deleted file mode 100644
index 1f7d88a..0000000
--- a/graphics/mapper/2.0/utils/vts/VtsHalGraphicsMapperTestUtils.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef VTS_HAL_GRAPHICS_MAPPER_UTILS
-#define VTS_HAL_GRAPHICS_MAPPER_UTILS
-
-#include <unordered_set>
-
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace mapper {
-namespace V2_0 {
-namespace tests {
-
-using android::hardware::graphics::allocator::V2_0::IAllocator;
-
-// A wrapper to IAllocator and IMapper.
-class Gralloc {
-   public:
-    Gralloc();
-    ~Gralloc();
-
-    // IAllocator methods
-
-    sp<IAllocator> getAllocator() const;
-
-    std::string dumpDebugInfo();
-
-    // When import is false, this simply calls IAllocator::allocate. When import
-    // is true, the returned buffers are also imported into the mapper.
-    //
-    // Either case, the returned buffers must be freed with freeBuffer.
-    std::vector<const native_handle_t*> allocate(const BufferDescriptor& descriptor, uint32_t count,
-                                                 bool import = true, uint32_t* outStride = nullptr);
-    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
-                                    bool import = true, uint32_t* outStride = nullptr);
-
-    // IMapper methods
-
-    sp<IMapper> getMapper() const;
-
-    BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
-
-    const native_handle_t* importBuffer(const hidl_handle& rawHandle);
-    void freeBuffer(const native_handle_t* bufferHandle);
-
-    // We use fd instead of hidl_handle in these functions to pass fences
-    // in and out of the mapper.  The ownership of the fd is always transferred
-    // with each of these functions.
-    void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-               const IMapper::Rect& accessRegion, int acquireFence);
-    YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-                          const IMapper::Rect& accessRegion, int acquireFence);
-    int unlock(const native_handle_t* bufferHandle);
-
-   private:
-    void init();
-    const native_handle_t* cloneBuffer(const hidl_handle& rawHandle);
-
-    sp<IAllocator> mAllocator;
-    sp<IMapper> mMapper;
-
-    // Keep track of all cloned and imported handles.  When a test fails with
-    // ASSERT_*, the destructor will free the handles for the test.
-    std::unordered_set<const native_handle_t*> mClonedBuffers;
-    std::unordered_set<const native_handle_t*> mImportedBuffers;
-};
-
-// Test environment for graphics.mapper.
-class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static GraphicsMapperHidlEnvironment* Instance() {
-        static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<IAllocator>();
-        registerTestService<IMapper>();
-    }
-};
-
-}  // namespace tests
-}  // namespace V2_0
-}  // namespace mapper
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
-
-#endif  // VTS_HAL_GRAPHICS_MAPPER_UTILS
diff --git a/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h b/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
new file mode 100644
index 0000000..6c2c9a6
--- /dev/null
+++ b/graphics/mapper/2.0/utils/vts/include/mapper-vts/2.0/MapperVts.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace vts {
+
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+
+// A wrapper to IAllocator and IMapper.
+class Gralloc {
+   public:
+    Gralloc(const std::string& allocatorServiceName = "default",
+            const std::string& mapperServiceName = "default");
+    ~Gralloc();
+
+    // IAllocator methods
+
+    sp<IAllocator> getAllocator() const;
+
+    std::string dumpDebugInfo();
+
+    // When import is false, this simply calls IAllocator::allocate. When import
+    // is true, the returned buffers are also imported into the mapper.
+    //
+    // Either case, the returned buffers must be freed with freeBuffer.
+    std::vector<const native_handle_t*> allocate(const BufferDescriptor& descriptor, uint32_t count,
+                                                 bool import = true, uint32_t* outStride = nullptr);
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import = true, uint32_t* outStride = nullptr);
+
+    // IMapper methods
+
+    sp<IMapper> getMapper() const;
+
+    BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
+    const native_handle_t* importBuffer(const hidl_handle& rawHandle);
+    void freeBuffer(const native_handle_t* bufferHandle);
+
+    // We use fd instead of hidl_handle in these functions to pass fences
+    // in and out of the mapper.  The ownership of the fd is always transferred
+    // with each of these functions.
+    void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+               const IMapper::Rect& accessRegion, int acquireFence);
+    YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                          const IMapper::Rect& accessRegion, int acquireFence);
+    int unlock(const native_handle_t* bufferHandle);
+
+   private:
+    void init(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+    const native_handle_t* cloneBuffer(const hidl_handle& rawHandle);
+
+    sp<IAllocator> mAllocator;
+    sp<IMapper> mMapper;
+
+    // Keep track of all cloned and imported handles.  When a test fails with
+    // ASSERT_*, the destructor will free the handles for the test.
+    std::unordered_set<const native_handle_t*> mClonedBuffers;
+    std::unordered_set<const native_handle_t*> mImportedBuffers;
+};
+
+}  // namespace vts
+}  // namespace V2_0
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.0/vts/OWNERS b/graphics/mapper/2.0/vts/OWNERS
new file mode 100644
index 0000000..ef69d7c
--- /dev/null
+++ b/graphics/mapper/2.0/vts/OWNERS
@@ -0,0 +1,6 @@
+# Graphics team
+olv@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
\ No newline at end of file
diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp
index 8093b08..969317a 100644
--- a/graphics/mapper/2.0/vts/functional/Android.bp
+++ b/graphics/mapper/2.0/vts/functional/Android.bp
@@ -18,14 +18,10 @@
     name: "VtsHalGraphicsMapperV2_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGraphicsMapperV2_0TargetTest.cpp"],
-    shared_libs: [
-        "libsync",
-    ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.common@1.0",
-        "libVtsHalGraphicsMapperTestUtils",
-        "libnativehelper",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
     ],
 }
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
index 21ea66d..aa9beff 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
@@ -18,24 +18,41 @@
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
-#include <sync/sync.h>
-#include "VtsHalGraphicsMapperTestUtils.h"
+#include <mapper-vts/2.0/MapperVts.h>
 
 namespace android {
 namespace hardware {
 namespace graphics {
 namespace mapper {
 namespace V2_0 {
-namespace tests {
+namespace vts {
 namespace {
 
 using android::hardware::graphics::common::V1_0::BufferUsage;
 using android::hardware::graphics::common::V1_0::PixelFormat;
 
+// Test environment for graphics.mapper.
+class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static GraphicsMapperHidlEnvironment* Instance() {
+        static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override {
+        registerTestService<IAllocator>();
+        registerTestService<IMapper>();
+    }
+};
+
 class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    protected:
     void SetUp() override {
-        ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+        ASSERT_NO_FATAL_FAILURE(
+            mGralloc = std::make_unique<Gralloc>(
+                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
+                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
 
         mDummyDescriptorInfo.width = 64;
         mDummyDescriptorInfo.height = 64;
@@ -167,7 +184,10 @@
 
     // free the imported handle with another mapper
     std::unique_ptr<Gralloc> anotherGralloc;
-    ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>());
+    ASSERT_NO_FATAL_FAILURE(
+        anotherGralloc = std::make_unique<Gralloc>(
+            GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
+            GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
     Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
     ASSERT_EQ(Error::NONE, error);
 
@@ -373,7 +393,7 @@
 }
 
 }  // namespace
-}  // namespace tests
+}  // namespace vts
 }  // namespace V2_0
 }  // namespace mapper
 }  // namespace graphics
@@ -381,7 +401,7 @@
 }  // namespace android
 
 int main(int argc, char** argv) {
-    using android::hardware::graphics::mapper::V2_0::tests::GraphicsMapperHidlEnvironment;
+    using android::hardware::graphics::mapper::V2_0::vts::GraphicsMapperHidlEnvironment;
     ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
     GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
diff --git a/graphics/mapper/2.1/Android.bp b/graphics/mapper/2.1/Android.bp
new file mode 100644
index 0000000..d917e59
--- /dev/null
+++ b/graphics/mapper/2.1/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.mapper@2.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    srcs: [
+        "IMapper.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
+
diff --git a/graphics/mapper/2.1/IMapper.hal b/graphics/mapper/2.1/IMapper.hal
new file mode 100644
index 0000000..6047e96
--- /dev/null
+++ b/graphics/mapper/2.1/IMapper.hal
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.mapper@2.1;
+
+import android.hardware.graphics.common@1.1::BufferUsage;
+import android.hardware.graphics.common@1.1::PixelFormat;
+import @2.0::BufferDescriptor;
+import @2.0::Error;
+import @2.0::IMapper;
+
+interface IMapper extends @2.0::IMapper {
+    /**
+     * This is the same as @2.0::IMapper::BufferDescriptorInfo except that it
+     * accepts @1.1::PixelFormat and @1.1::BufferUsage.
+     */
+    struct BufferDescriptorInfo {
+        /**
+         * The width specifies how many columns of pixels must be in the
+         * allocated buffer, but does not necessarily represent the offset in
+         * columns between the same column in adjacent rows. The rows may be
+         * padded.
+         */
+        uint32_t width;
+
+       /**
+        * The height specifies how many rows of pixels must be in the
+        * allocated buffer.
+        */
+        uint32_t height;
+
+       /**
+        * The number of image layers that must be in the allocated buffer.
+        */
+        uint32_t layerCount;
+
+        /** Buffer pixel format. */
+        PixelFormat format;
+
+        /**
+         * Buffer usage mask; valid flags can be found in the definition of
+         * BufferUsage.
+         */
+        bitfield<BufferUsage> usage;
+    };
+
+    /**
+     * Validate that the buffer can be safely accessed by a caller who assumes
+     * the specified descriptorInfo and stride. This must at least validate
+     * that the buffer size is large enough. Validating the buffer against
+     * individual buffer attributes is optional.
+     *
+     * @param buffer is the buffer to validate against.
+     * @param descriptorInfo specifies the attributes of the buffer.
+     * @param stride is the buffer stride returned by IAllocator::allocate.
+     * @return error is NONE upon success. Otherwise,
+     *                  BAD_BUFFER when the buffer is invalid.
+     *                  BAD_VALUE when buffer cannot be safely accessed
+     */
+    validateBufferSize(pointer buffer,
+                       BufferDescriptorInfo descriptorInfo,
+                       uint32_t stride)
+            generates (Error error);
+
+    /**
+     * Get the transport size of a buffer. An imported buffer handle is a raw
+     * buffer handle with the process-local runtime data appended. This
+     * function, for example, allows a caller to omit the process-local
+     * runtime data at the tail when serializing the imported buffer handle.
+     *
+     * Note that a client might or might not omit the process-local runtime
+     * data when sending an imported buffer handle. The mapper must support
+     * both cases on the receiving end.
+     *
+     * @param buffer is the buffer to get the transport size from.
+     * @return error is NONE upon success. Otherwise,
+     *                  BAD_BUFFER when the buffer is invalid.
+     * @return numFds is the number of file descriptors needed for transport.
+     * @return numInts is the number of integers needed for transport.
+     */
+    getTransportSize(pointer buffer)
+            generates (Error error,
+                       uint32_t numFds,
+                       uint32_t numInts);
+
+    /**
+     * This is the same as @2.0::IMapper::createDescriptor except that it
+     * accepts @2.1::IMapper::BufferDescriptorInfo.
+     *
+     * Creates a buffer descriptor. The descriptor can be used with IAllocator
+     * to allocate buffers.
+     *
+     * Since the buffer descriptor fully describes a buffer, any device
+     * dependent or device independent checks must be performed here whenever
+     * possible. Specifically, when layered buffers are not supported, this
+     * function must return UNSUPPORTED if layerCount is great than 1.
+     *
+     * @param descriptorInfo specifies the attributes of the descriptor.
+     * @return error is NONE upon success. Otherwise,
+     *                  BAD_VALUE when any of the specified attributes is
+     *                            invalid or conflicting.
+     *                  NO_RESOURCES when the creation cannot be fullfilled at
+     *                               this time.
+     *                  UNSUPPORTED when any of the specified attributes is
+     *                              not supported.
+     * @return descriptor is the newly created buffer descriptor.
+     */
+    createDescriptor_2_1(BufferDescriptorInfo descriptorInfo)
+              generates (Error error,
+                         BufferDescriptor descriptor);
+};
diff --git a/graphics/mapper/2.1/default/Android.bp b/graphics/mapper/2.1/default/Android.bp
new file mode 100644
index 0000000..aa204a0
--- /dev/null
+++ b/graphics/mapper/2.1/default/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "android.hardware.graphics.mapper@2.0-impl-2.1",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: ["passthrough.cpp"],
+    header_libs: [
+        "android.hardware.graphics.mapper@2.1-passthrough",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libsync",
+        "libutils",
+    ],
+}
diff --git a/graphics/mapper/2.1/default/OWNERS b/graphics/mapper/2.1/default/OWNERS
new file mode 100644
index 0000000..3aa5fa1
--- /dev/null
+++ b/graphics/mapper/2.1/default/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/mapper/2.1/default/passthrough.cpp b/graphics/mapper/2.1/default/passthrough.cpp
new file mode 100644
index 0000000..c7f0cf5
--- /dev/null
+++ b/graphics/mapper/2.1/default/passthrough.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright 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.
+ */
+
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <mapper-passthrough/2.1/GrallocLoader.h>
+
+using android::hardware::graphics::mapper::V2_1::IMapper;
+using android::hardware::graphics::mapper::V2_1::passthrough::GrallocLoader;
+
+extern "C" IMapper* HIDL_FETCH_IMapper(const char* /*name*/) {
+    return GrallocLoader::load();
+}
diff --git a/graphics/mapper/2.1/utils/OWNERS b/graphics/mapper/2.1/utils/OWNERS
new file mode 100644
index 0000000..3aa5fa1
--- /dev/null
+++ b/graphics/mapper/2.1/utils/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/mapper/2.1/utils/hal/Android.bp b/graphics/mapper/2.1/utils/hal/Android.bp
new file mode 100644
index 0000000..2a4cc6e
--- /dev/null
+++ b/graphics/mapper/2.1/utils/hal/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+    name: "android.hardware.graphics.mapper@2.1-hal",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    shared_libs: [
+        "android.hardware.graphics.mapper@2.1",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.mapper@2.1",
+    ],
+    header_libs: [
+        "android.hardware.graphics.mapper@2.0-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.mapper@2.0-hal",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/Mapper.h b/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/Mapper.h
new file mode 100644
index 0000000..038f572
--- /dev/null
+++ b/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/Mapper.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Mapper.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <mapper-hal/2.0/Mapper.h>
+#include <mapper-hal/2.1/MapperHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace hal {
+
+namespace detail {
+
+// MapperImpl implements V2_*::IMapper on top of V2_*::hal::MapperHal
+template <typename Interface, typename Hal>
+class MapperImpl : public V2_0::hal::detail::MapperImpl<Interface, Hal> {
+   public:
+    // IMapper 2.1 interface
+    Return<Error> validateBufferSize(void* buffer,
+                                     const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                     uint32_t stride) {
+        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        if (!bufferHandle) {
+            return Error::BAD_BUFFER;
+        }
+
+        return mHal->validateBufferSize(bufferHandle, descriptorInfo, stride);
+    }
+
+    Return<void> getTransportSize(void* buffer, IMapper::getTransportSize_cb hidl_cb) {
+        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        if (!bufferHandle) {
+            hidl_cb(Error::BAD_BUFFER, 0, 0);
+            return Void();
+        }
+
+        uint32_t numFds = 0;
+        uint32_t numInts = 0;
+        Error error = mHal->getTransportSize(bufferHandle, &numFds, &numInts);
+        hidl_cb(error, numFds, numInts);
+        return Void();
+    }
+
+    Return<void> createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                      IMapper::createDescriptor_2_1_cb hidl_cb) override {
+        BufferDescriptor descriptor;
+        Error error = mHal->createDescriptor_2_1(descriptorInfo, &descriptor);
+        hidl_cb(error, descriptor);
+        return Void();
+    }
+
+   private:
+    using BaseType2_0 = V2_0::hal::detail::MapperImpl<Interface, Hal>;
+    using BaseType2_0::getImportedBuffer;
+    using BaseType2_0::mHal;
+};
+
+}  // namespace detail
+
+using Mapper = detail::MapperImpl<IMapper, MapperHal>;
+
+}  // namespace hal
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/MapperHal.h b/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/MapperHal.h
new file mode 100644
index 0000000..e488fab
--- /dev/null
+++ b/graphics/mapper/2.1/utils/hal/include/mapper-hal/2.1/MapperHal.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <mapper-hal/2.0/MapperHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace hal {
+
+using V2_0::BufferDescriptor;
+using V2_0::Error;
+
+class MapperHal : public V2_0::hal::MapperHal {
+   public:
+    virtual ~MapperHal() = default;
+
+    // superceded by createDescriptor_2_1
+    Error createDescriptor(const V2_0::IMapper::BufferDescriptorInfo& descriptorInfo,
+                           BufferDescriptor* outDescriptor) override {
+        return createDescriptor_2_1(
+            IMapper::BufferDescriptorInfo{
+                descriptorInfo.width, descriptorInfo.height, descriptorInfo.layerCount,
+                static_cast<common::V1_1::PixelFormat>(descriptorInfo.format), descriptorInfo.usage,
+            },
+            outDescriptor);
+    }
+
+    // validate the buffer can be safely accessed with the specified
+    // descriptorInfo and stride
+    virtual Error validateBufferSize(const native_handle_t* bufferHandle,
+                                     const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                     uint32_t stride) = 0;
+
+    // get the transport size of a buffer handle.  It can be smaller than or
+    // equal to the size of the buffer handle.
+    virtual Error getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+                                   uint32_t* outNumInts) = 0;
+
+    // create a BufferDescriptor
+    virtual Error createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                       BufferDescriptor* outDescriptor) = 0;
+};
+
+}  // namespace hal
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/passthrough/Android.bp b/graphics/mapper/2.1/utils/passthrough/Android.bp
new file mode 100644
index 0000000..6946a53
--- /dev/null
+++ b/graphics/mapper/2.1/utils/passthrough/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+    name: "android.hardware.graphics.mapper@2.1-passthrough",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    shared_libs: [
+        "android.hardware.graphics.mapper@2.1",
+        "libhardware",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.mapper@2.1",
+        "libhardware",
+    ],
+    header_libs: [
+        "android.hardware.graphics.mapper@2.0-passthrough",
+        "android.hardware.graphics.mapper@2.1-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.mapper@2.0-passthrough",
+        "android.hardware.graphics.mapper@2.1-hal",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h
new file mode 100644
index 0000000..b704fdb
--- /dev/null
+++ b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc0Hal.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <mapper-hal/2.1/MapperHal.h>
+#include <mapper-passthrough/2.0/Gralloc0Hal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace passthrough {
+
+namespace detail {
+
+using V2_0::BufferDescriptor;
+using V2_0::Error;
+
+// Gralloc0HalImpl implements V2_*::hal::MapperHal on top of gralloc0
+template <typename Hal>
+class Gralloc0HalImpl : public V2_0::passthrough::detail::Gralloc0HalImpl<Hal> {
+   public:
+    Error validateBufferSize(const native_handle_t* /*bufferHandle*/,
+                             const IMapper::BufferDescriptorInfo& /*descriptorInfo*/,
+                             uint32_t /*stride*/) override {
+        // need a gralloc0 extension to really validate
+        return Error::NONE;
+    }
+
+    Error getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+                           uint32_t* outNumInts) override {
+        // need a gralloc0 extension to get the transport size
+        *outNumFds = bufferHandle->numFds;
+        *outNumInts = bufferHandle->numInts;
+        return Error::NONE;
+    }
+
+    Error createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                               BufferDescriptor* outDescriptor) override {
+        return createDescriptor(
+            V2_0::IMapper::BufferDescriptorInfo{
+                descriptorInfo.width, descriptorInfo.height, descriptorInfo.layerCount,
+                static_cast<common::V1_0::PixelFormat>(descriptorInfo.format), descriptorInfo.usage,
+            },
+            outDescriptor);
+    }
+
+   private:
+    using BaseType2_0 = V2_0::passthrough::detail::Gralloc0HalImpl<Hal>;
+    using BaseType2_0::createDescriptor;
+};
+
+}  // namespace detail
+
+using Gralloc0Hal = detail::Gralloc0HalImpl<hal::MapperHal>;
+
+}  // namespace passthrough
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h
new file mode 100644
index 0000000..8b695e4
--- /dev/null
+++ b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/Gralloc1Hal.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <hardware/gralloc1.h>
+#include <mapper-hal/2.1/MapperHal.h>
+#include <mapper-passthrough/2.0/Gralloc1Hal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace passthrough {
+
+using V2_0::BufferDescriptor;
+using V2_0::Error;
+
+namespace detail {
+
+// Gralloc1HalImpl implements V2_*::hal::MapperHal on top of gralloc1
+template <typename Hal>
+class Gralloc1HalImpl : public V2_0::passthrough::detail::Gralloc1HalImpl<Hal> {
+   public:
+    Error validateBufferSize(const native_handle_t* bufferHandle,
+                             const IMapper::BufferDescriptorInfo& descriptorInfo,
+                             uint32_t stride) override {
+        uint32_t bufferWidth;
+        uint32_t bufferHeight;
+        uint32_t bufferLayerCount;
+        int32_t bufferFormat;
+        uint64_t bufferProducerUsage;
+        uint64_t bufferConsumerUsage;
+        uint32_t bufferStride;
+
+        int32_t error = mDispatch.getDimensions(mDevice, bufferHandle, &bufferWidth, &bufferHeight);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        error = mDispatch.getLayerCount(mDevice, bufferHandle, &bufferLayerCount);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        error = mDispatch.getFormat(mDevice, bufferHandle, &bufferFormat);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        error = mDispatch.getProducerUsage(mDevice, bufferHandle, &bufferProducerUsage);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        error = mDispatch.getConsumerUsage(mDevice, bufferHandle, &bufferConsumerUsage);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+        error = mDispatch.getStride(mDevice, bufferHandle, &bufferStride);
+        if (error != GRALLOC1_ERROR_NONE) {
+            return toError(error);
+        }
+
+        // TODO format? usage? width > stride?
+        // need a gralloc1 extension to really validate
+        (void)bufferFormat;
+        (void)bufferProducerUsage;
+        (void)bufferConsumerUsage;
+
+        if (descriptorInfo.width > bufferWidth || descriptorInfo.height > bufferHeight ||
+            descriptorInfo.layerCount > bufferLayerCount || stride > bufferStride) {
+            return Error::BAD_VALUE;
+        }
+
+        return Error::NONE;
+    }
+
+    Error getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+                           uint32_t* outNumInts) override {
+        // need a gralloc1 extension to get the transport size
+        *outNumFds = bufferHandle->numFds;
+        *outNumInts = bufferHandle->numInts;
+        return Error::NONE;
+    }
+
+    Error createDescriptor_2_1(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                               BufferDescriptor* outDescriptor) override {
+        return createDescriptor(
+            V2_0::IMapper::BufferDescriptorInfo{
+                descriptorInfo.width, descriptorInfo.height, descriptorInfo.layerCount,
+                static_cast<common::V1_0::PixelFormat>(descriptorInfo.format), descriptorInfo.usage,
+            },
+            outDescriptor);
+    }
+
+   protected:
+    bool initDispatch() override {
+        if (!BaseType2_0::initDispatch()) {
+            return false;
+        }
+
+        if (!initDispatch(GRALLOC1_FUNCTION_GET_DIMENSIONS, &mDispatch.getDimensions) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_LAYER_COUNT, &mDispatch.getLayerCount) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_FORMAT, &mDispatch.getFormat) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_PRODUCER_USAGE, &mDispatch.getProducerUsage) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_CONSUMER_USAGE, &mDispatch.getConsumerUsage) ||
+            !initDispatch(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    struct {
+        GRALLOC1_PFN_GET_DIMENSIONS getDimensions;
+        GRALLOC1_PFN_GET_LAYER_COUNT getLayerCount;
+        GRALLOC1_PFN_GET_FORMAT getFormat;
+        GRALLOC1_PFN_GET_PRODUCER_USAGE getProducerUsage;
+        GRALLOC1_PFN_GET_CONSUMER_USAGE getConsumerUsage;
+        GRALLOC1_PFN_GET_STRIDE getStride;
+    } mDispatch = {};
+
+   private:
+    using BaseType2_0 = V2_0::passthrough::detail::Gralloc1HalImpl<Hal>;
+    using BaseType2_0::createDescriptor;
+    using BaseType2_0::initDispatch;
+    using BaseType2_0::mDevice;
+    using BaseType2_0::toError;
+};
+
+}  // namespace detail
+
+using Gralloc1Hal = detail::Gralloc1HalImpl<hal::MapperHal>;
+
+}  // namespace passthrough
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/GrallocLoader.h b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/GrallocLoader.h
new file mode 100644
index 0000000..f2c67db
--- /dev/null
+++ b/graphics/mapper/2.1/utils/passthrough/include/mapper-passthrough/2.1/GrallocLoader.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <log/log.h>
+#include <mapper-hal/2.1/Mapper.h>
+#include <mapper-hal/2.1/MapperHal.h>
+#include <mapper-passthrough/2.0/GrallocLoader.h>
+#include <mapper-passthrough/2.1/Gralloc0Hal.h>
+#include <mapper-passthrough/2.1/Gralloc1Hal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace passthrough {
+
+class GrallocLoader : public V2_0::passthrough::GrallocLoader {
+   public:
+    static IMapper* load() {
+        const hw_module_t* module = loadModule();
+        if (!module) {
+            return nullptr;
+        }
+        auto hal = createHal(module);
+        if (!hal) {
+            return nullptr;
+        }
+        return createMapper(std::move(hal));
+    }
+
+    // create a MapperHal instance
+    static std::unique_ptr<hal::MapperHal> createHal(const hw_module_t* module) {
+        int major = getModuleMajorApiVersion(module);
+        switch (major) {
+            case 1: {
+                auto hal = std::make_unique<Gralloc1Hal>();
+                return hal->initWithModule(module) ? std::move(hal) : nullptr;
+            }
+            case 0: {
+                auto hal = std::make_unique<Gralloc0Hal>();
+                return hal->initWithModule(module) ? std::move(hal) : nullptr;
+            }
+            default:
+                ALOGE("unknown gralloc module major version %d", major);
+                return nullptr;
+        }
+    }
+
+    // create an IAllocator instance
+    static IMapper* createMapper(std::unique_ptr<hal::MapperHal> hal) {
+        auto mapper = std::make_unique<V2_0::passthrough::GrallocMapper<hal::Mapper>>();
+        return mapper->init(std::move(hal)) ? mapper.release() : nullptr;
+    }
+};
+
+}  // namespace passthrough
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/vts/Android.bp b/graphics/mapper/2.1/utils/vts/Android.bp
new file mode 100644
index 0000000..ca02aad
--- /dev/null
+++ b/graphics/mapper/2.1/utils/vts/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.graphics.mapper@2.1-vts",
+    defaults: ["hidl_defaults"],
+    srcs: ["MapperVts.cpp"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetTestBase",
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1",
+    ],
+    export_static_lib_headers: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/2.1/utils/vts/MapperVts.cpp b/graphics/mapper/2.1/utils/vts/MapperVts.cpp
new file mode 100644
index 0000000..0aaa926
--- /dev/null
+++ b/graphics/mapper/2.1/utils/vts/MapperVts.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mapper-vts/2.1/MapperVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace vts {
+
+using V2_0::Error;
+
+// abuse VTS to check binary compatibility between BufferDescriptorInfos
+using OldBufferDescriptorInfo =
+    android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo;
+static_assert(sizeof(OldBufferDescriptorInfo) == sizeof(IMapper::BufferDescriptorInfo) &&
+                  offsetof(OldBufferDescriptorInfo, width) ==
+                      offsetof(IMapper::BufferDescriptorInfo, width) &&
+                  offsetof(OldBufferDescriptorInfo, height) ==
+                      offsetof(IMapper::BufferDescriptorInfo, height) &&
+                  offsetof(OldBufferDescriptorInfo, layerCount) ==
+                      offsetof(IMapper::BufferDescriptorInfo, layerCount) &&
+                  offsetof(OldBufferDescriptorInfo, format) ==
+                      offsetof(IMapper::BufferDescriptorInfo, format) &&
+                  offsetof(OldBufferDescriptorInfo, usage) ==
+                      offsetof(IMapper::BufferDescriptorInfo, usage),
+              "");
+
+Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName)
+    : V2_0::vts::Gralloc(allocatorServiceName, mapperServiceName) {
+    if (::testing::Test::HasFatalFailure()) {
+        return;
+    }
+    init();
+}
+
+void Gralloc::init() {
+    mMapperV2_1 = IMapper::castFrom(V2_0::vts::Gralloc::getMapper());
+    ASSERT_NE(nullptr, mMapperV2_1.get()) << "failed to get mapper 2.1 service";
+}
+
+sp<IMapper> Gralloc::getMapper() const {
+    return mMapperV2_1;
+}
+
+bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle,
+                                 const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                 uint32_t stride) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    Error error = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride);
+    return error == Error::NONE;
+}
+
+void Gralloc::getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+                               uint32_t* outNumInts) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    *outNumFds = 0;
+    *outNumInts = 0;
+    mMapperV2_1->getTransportSize(
+        buffer, [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) {
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to get transport size";
+            ASSERT_GE(bufferHandle->numFds, int(tmpNumFds)) << "invalid numFds " << tmpNumFds;
+            ASSERT_GE(bufferHandle->numInts, int(tmpNumInts)) << "invalid numInts " << tmpNumInts;
+
+            *outNumFds = tmpNumFds;
+            *outNumInts = tmpNumInts;
+        });
+}
+
+BufferDescriptor Gralloc::createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+    BufferDescriptor descriptor;
+    mMapperV2_1->createDescriptor_2_1(
+        descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
+            descriptor = tmpDescriptor;
+        });
+
+    return descriptor;
+}
+
+const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                         bool import, uint32_t* outStride) {
+    BufferDescriptor descriptor = createDescriptor(descriptorInfo);
+    if (::testing::Test::HasFatalFailure()) {
+        return nullptr;
+    }
+
+    auto buffers = V2_0::vts::Gralloc::allocate(descriptor, 1, import, outStride);
+    if (::testing::Test::HasFatalFailure()) {
+        return nullptr;
+    }
+
+    return buffers[0];
+}
+
+}  // namespace vts
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h b/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h
new file mode 100644
index 0000000..b7fa751
--- /dev/null
+++ b/graphics/mapper/2.1/utils/vts/include/mapper-vts/2.1/MapperVts.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <mapper-vts/2.0/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace vts {
+
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using V2_0::BufferDescriptor;
+
+// A wrapper to IAllocator and IMapper.
+class Gralloc : public V2_0::vts::Gralloc {
+   public:
+    Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+
+    sp<IMapper> getMapper() const;
+
+    bool validateBufferSize(const native_handle_t* bufferHandle,
+                            const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride);
+    void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+                          uint32_t* outNumInts);
+
+    BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
+    const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import = true, uint32_t* outStride = nullptr);
+
+   protected:
+    void init();
+
+    sp<IMapper> mMapperV2_1;
+};
+
+}  // namespace vts
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/mapper/2.1/vts/OWNERS b/graphics/mapper/2.1/vts/OWNERS
new file mode 100644
index 0000000..ef69d7c
--- /dev/null
+++ b/graphics/mapper/2.1/vts/OWNERS
@@ -0,0 +1,6 @@
+# Graphics team
+olv@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
\ No newline at end of file
diff --git a/graphics/mapper/2.1/vts/functional/Android.bp b/graphics/mapper/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..ac67af8
--- /dev/null
+++ b/graphics/mapper/2.1/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalGraphicsMapperV2_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalGraphicsMapperV2_1TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1-vts",
+    ],
+}
diff --git a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
new file mode 100644
index 0000000..5e7cf93
--- /dev/null
+++ b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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 "VtsHalGraphicsMapperV2_1TargetTest"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <mapper-vts/2.1/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_1 {
+namespace vts {
+namespace {
+
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+using android::hardware::graphics::common::V1_1::PixelFormat;
+using V2_0::Error;
+
+// Test environment for graphics.mapper.
+class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static GraphicsMapperHidlEnvironment* Instance() {
+        static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override {
+        registerTestService<IAllocator>();
+        registerTestService<IMapper>();
+    }
+};
+
+class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(
+            mGralloc = std::make_unique<Gralloc>(
+                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
+                GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+
+        mDummyDescriptorInfo.width = 64;
+        mDummyDescriptorInfo.height = 64;
+        mDummyDescriptorInfo.layerCount = 1;
+        mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
+        mDummyDescriptorInfo.usage =
+            static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+    }
+
+    void TearDown() override {}
+
+    std::unique_ptr<Gralloc> mGralloc;
+    IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
+};
+
+/**
+ * Test that IMapper::validateBufferSize works.
+ */
+TEST_F(GraphicsMapperHidlTest, ValidateBufferSizeBasic) {
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true, &stride));
+
+    ASSERT_TRUE(mGralloc->validateBufferSize(bufferHandle, mDummyDescriptorInfo, stride));
+
+    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
+}
+
+/**
+ * Test IMapper::validateBufferSize with invalid buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, ValidateBufferSizeBadBuffer) {
+    native_handle_t* invalidHandle = nullptr;
+    Error ret = mGralloc->getMapper()->validateBufferSize(invalidHandle, mDummyDescriptorInfo,
+                                                          mDummyDescriptorInfo.width);
+    ASSERT_EQ(Error::BAD_BUFFER, ret)
+        << "validateBufferSize with nullptr did not fail with BAD_BUFFER";
+
+    invalidHandle = native_handle_create(0, 0);
+    ret = mGralloc->getMapper()->validateBufferSize(invalidHandle, mDummyDescriptorInfo,
+                                                    mDummyDescriptorInfo.width);
+    ASSERT_EQ(Error::BAD_BUFFER, ret)
+        << "validateBufferSize with invalid handle did not fail with BAD_BUFFER";
+    native_handle_delete(invalidHandle);
+
+    native_handle_t* rawBufferHandle;
+    ASSERT_NO_FATAL_FAILURE(rawBufferHandle = const_cast<native_handle_t*>(
+                                mGralloc->allocate(mDummyDescriptorInfo, false)));
+    ret = mGralloc->getMapper()->validateBufferSize(rawBufferHandle, mDummyDescriptorInfo,
+                                                    mDummyDescriptorInfo.width);
+    ASSERT_EQ(Error::BAD_BUFFER, ret)
+        << "validateBufferSize with raw buffer handle did not fail with BAD_BUFFER";
+    native_handle_delete(rawBufferHandle);
+}
+
+/**
+ * Test IMapper::validateBufferSize with invalid descriptor and/or stride.
+ */
+TEST_F(GraphicsMapperHidlTest, ValidateBufferSizeBadValue) {
+    auto info = mDummyDescriptorInfo;
+    info.width = 1024;
+    info.height = 1024;
+    info.layerCount = 1;
+    info.format = PixelFormat::RGBA_8888;
+
+    native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(
+        bufferHandle = const_cast<native_handle_t*>(mGralloc->allocate(info, true, &stride)));
+
+    // All checks below test if a 8MB buffer can fit in a 4MB buffer.
+    info.width *= 2;
+    Error ret = mGralloc->getMapper()->validateBufferSize(bufferHandle, info, stride);
+    ASSERT_EQ(Error::BAD_VALUE, ret)
+        << "validateBufferSize with bad width did not fail with BAD_VALUE";
+    info.width /= 2;
+
+    info.height *= 2;
+    ret = mGralloc->getMapper()->validateBufferSize(bufferHandle, info, stride);
+    ASSERT_EQ(Error::BAD_VALUE, ret)
+        << "validateBufferSize with bad height did not fail with BAD_VALUE";
+    info.height /= 2;
+
+    info.layerCount *= 2;
+    ret = mGralloc->getMapper()->validateBufferSize(bufferHandle, info, stride);
+    ASSERT_EQ(Error::BAD_VALUE, ret)
+        << "validateBufferSize with bad layer count did not fail with BAD_VALUE";
+    info.layerCount /= 2;
+
+    info.format = PixelFormat::RGBA_FP16;
+    ret = mGralloc->getMapper()->validateBufferSize(bufferHandle, info, stride);
+    ASSERT_EQ(Error::BAD_VALUE, ret)
+        << "validateBufferSize with bad format did not fail with BAD_VALUE";
+    info.format = PixelFormat::RGBA_8888;
+
+    ret = mGralloc->getMapper()->validateBufferSize(bufferHandle, mDummyDescriptorInfo, stride * 2);
+    ASSERT_EQ(Error::BAD_VALUE, ret)
+        << "validateBufferSize with bad stride did not fail with BAD_VALUE";
+
+    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
+}
+
+/**
+ * Test IMapper::getTransportSize.
+ */
+TEST_F(GraphicsMapperHidlTest, GetTransportSizeBasic) {
+    const native_handle_t* bufferHandle;
+    uint32_t numFds;
+    uint32_t numInts;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+    ASSERT_NO_FATAL_FAILURE(mGralloc->getTransportSize(bufferHandle, &numFds, &numInts));
+    ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
+}
+
+/**
+ * Test IMapper::getTransportSize with invalid buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, GetTransportSizeBadBuffer) {
+    native_handle_t* invalidHandle = nullptr;
+    mGralloc->getMapper()->getTransportSize(
+        invalidHandle, [&](const auto& tmpError, const auto&, const auto&) {
+            ASSERT_EQ(Error::BAD_BUFFER, tmpError)
+                << "getTransportSize with nullptr did not fail with BAD_BUFFER";
+        });
+
+    invalidHandle = native_handle_create(0, 0);
+    mGralloc->getMapper()->getTransportSize(
+        invalidHandle, [&](const auto& tmpError, const auto&, const auto&) {
+            ASSERT_EQ(Error::BAD_BUFFER, tmpError)
+                << "getTransportSize with invalid handle did not fail with BAD_BUFFER";
+        });
+    native_handle_delete(invalidHandle);
+
+    native_handle_t* rawBufferHandle;
+    ASSERT_NO_FATAL_FAILURE(rawBufferHandle = const_cast<native_handle_t*>(
+                                mGralloc->allocate(mDummyDescriptorInfo, false)));
+    mGralloc->getMapper()->getTransportSize(
+        invalidHandle, [&](const auto& tmpError, const auto&, const auto&) {
+            ASSERT_EQ(Error::BAD_BUFFER, tmpError)
+                << "getTransportSize with raw buffer handle did not fail with BAD_BUFFER";
+        });
+    native_handle_delete(rawBufferHandle);
+}
+
+/**
+ * Test IMapper::createDescriptor with valid descriptor info.
+ */
+TEST_F(GraphicsMapperHidlTest, CreateDescriptor_2_1Basic) {
+    ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
+}
+
+/**
+ * Test IMapper::createDescriptor with invalid descriptor info.
+ */
+TEST_F(GraphicsMapperHidlTest, CreateDescriptor_2_1Negative) {
+    auto info = mDummyDescriptorInfo;
+    info.width = 0;
+    mGralloc->getMapper()->createDescriptor_2_1(info, [&](const auto& tmpError, const auto&) {
+        EXPECT_EQ(Error::BAD_VALUE, tmpError) << "createDescriptor did not fail with BAD_VALUE";
+    });
+}
+
+}  // namespace
+}  // namespace vts
+}  // namespace V2_1
+}  // namespace mapper
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    using android::hardware::graphics::mapper::V2_1::vts::GraphicsMapperHidlEnvironment;
+    ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
+
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+
+    return status;
+}
diff --git a/health/1.0/default/android.hardware.health@1.0-service.rc b/health/1.0/default/android.hardware.health@1.0-service.rc
index 13cd7a5..d74a07e 100644
--- a/health/1.0/default/android.hardware.health@1.0-service.rc
+++ b/health/1.0/default/android.hardware.health@1.0-service.rc
@@ -1,4 +1,4 @@
-service health-hal-1-0 /vendor/bin/hw/android.hardware.health@1.0-service
+service vendor.health-hal-1-0 /vendor/bin/hw/android.hardware.health@1.0-service
     class hal
     user system
     group system
diff --git a/health/2.0/Android.bp b/health/2.0/Android.bp
index 4a4f24b..0325467 100644
--- a/health/2.0/Android.bp
+++ b/health/2.0/Android.bp
@@ -16,8 +16,11 @@
         "android.hidl.base@1.0",
     ],
     types: [
+        "DiskStats",
         "HealthInfo",
         "Result",
+        "StorageAttribute",
+        "StorageInfo",
     ],
     gen_java: true,
 }
diff --git a/health/2.0/IHealth.hal b/health/2.0/IHealth.hal
index 3e10701..230b5d0 100644
--- a/health/2.0/IHealth.hal
+++ b/health/2.0/IHealth.hal
@@ -69,7 +69,7 @@
      *                NOT_SUPPORTED if this property is not supported
      *                 (e.g. the file that stores this property does not exist),
      *                UNKNOWN for other errors.
-     * @return value battery capacity, or INT32_MIN if not successful.
+     * @return value battery capacity, or 0 if not successful.
      */
     getChargeCounter() generates (Result result, int32_t value);
 
@@ -84,7 +84,7 @@
      *                NOT_SUPPORTED if this property is not supported
      *                 (e.g. the file that stores this property does not exist),
      *                UNKNOWN for other errors.
-     * @return value instantaneous battery current, or INT32_MIN if not
+     * @return value instantaneous battery current, or 0 if not
      *               successful.
      */
     getCurrentNow() generates (Result result, int32_t value);
@@ -101,7 +101,7 @@
      *                NOT_SUPPORTED if this property is not supported
      *                 (e.g. the file that stores this property does not exist),
      *                UNKNOWN for other errors.
-     * @return value average battery current, or INT32_MIN if not successful.
+     * @return value average battery current, or 0 if not successful.
      */
     getCurrentAverage() generates (Result result, int32_t value);
 
@@ -113,7 +113,7 @@
      *                NOT_SUPPORTED if this property is not supported
      *                 (e.g. the file that stores this property does not exist),
      *                UNKNOWN for other errors.
-     * @return value remaining battery capacity, or INT32_MIN if not successful.
+     * @return value remaining battery capacity, or 0 if not successful.
      */
     getCapacity() generates (Result result, int32_t value);
 
@@ -123,7 +123,7 @@
      * @return result SUCCESS if successful,
      *                NOT_SUPPORTED if this property is not supported,
      *                UNKNOWN for other errors.
-     * @return value remaining energy, or INT64_MIN if not successful.
+     * @return value remaining energy, or 0 if not successful.
      */
     getEnergyCounter() generates (Result result, int64_t value);
 
@@ -137,4 +137,38 @@
      * @return value charge status, or UNKNOWN if not successful.
      */
     getChargeStatus() generates (Result result, BatteryStatus value);
+
+    /**
+     * Get storage info.
+     *
+     * @return result SUCCESS if successful,
+     *                NOT_SUPPORTED if this property is not supported,
+     *                UNKNOWN other errors.
+     * @return value vector of StorageInfo structs, to be ignored if result is not
+     *               SUCCESS.
+     */
+    getStorageInfo() generates (Result result, vec<StorageInfo> value);
+
+    /**
+     * Gets disk statistics (number of reads/writes processed, number of I/O
+     * operations in flight etc).
+     *
+     * @return result SUCCESS if successful,
+     *                NOT_SUPPORTED if this property is not supported,
+     *                UNKNOWN other errors.
+     * @return value vector of disk statistics, to be ignored if result is not SUCCESS.
+     *               The mapping is index 0->sda, 1->sdb and so on.
+     */
+    getDiskStats() generates (Result result, vec<DiskStats> value);
+
+    /**
+     * Get Health Information.
+     *
+     * @return result SUCCESS if successful,
+     *                NOT_SUPPORTED if this API is not supported,
+     *                UNKNOWN for other errors.
+     * @return value  Health information, to be ignored if result is not
+     *                SUCCESS.
+     */
+    getHealthInfo() generates (Result result, @2.0::HealthInfo value);
 };
diff --git a/health/2.0/default/Android.bp b/health/2.0/default/Android.bp
new file mode 100644
index 0000000..8eb02e0
--- /dev/null
+++ b/health/2.0/default/Android.bp
@@ -0,0 +1,28 @@
+cc_library_static {
+    name: "android.hardware.health@2.0-impl",
+    vendor_available: true,
+    srcs: [
+        "Health.cpp",
+        "healthd_common.cpp",
+    ],
+
+    cflags: ["-DHEALTHD_USE_HEALTH_2_0"],
+
+    export_include_dirs: ["include"],
+
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libutils",
+        "libcutils",
+        "android.hardware.health@2.0",
+    ],
+
+    static_libs: [
+        "libbatterymonitor",
+        "android.hardware.health@1.0-convert",
+    ],
+}
diff --git a/health/2.0/default/Health.cpp b/health/2.0/default/Health.cpp
new file mode 100644
index 0000000..7a3e650
--- /dev/null
+++ b/health/2.0/default/Health.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "android.hardware.health@2.0-impl"
+#include <android-base/logging.h>
+
+#include <health2/Health.h>
+
+#include <hal_conversion.h>
+#include <hidl/HidlTransportSupport.h>
+
+extern void healthd_battery_update_internal(bool);
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+namespace implementation {
+
+sp<Health> Health::instance_;
+
+Health::Health(struct healthd_config* c) {
+    // TODO(b/69268160): remove when libhealthd is removed.
+    healthd_board_init(c);
+    battery_monitor_ = std::make_unique<BatteryMonitor>();
+    battery_monitor_->init(c);
+}
+
+// Methods from IHealth follow.
+Return<Result> Health::registerCallback(const sp<IHealthInfoCallback>& callback) {
+    if (callback == nullptr) {
+        return Result::SUCCESS;
+    }
+
+    {
+        std::lock_guard<std::mutex> _lock(callbacks_lock_);
+        callbacks_.push_back(callback);
+        // unlock
+    }
+
+    auto linkRet = callback->linkToDeath(this, 0u /* cookie */);
+    if (!linkRet.withDefault(false)) {
+        LOG(WARNING) << __func__ << "Cannot link to death: "
+                     << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
+        // ignore the error
+    }
+
+    return update();
+}
+
+bool Health::unregisterCallbackInternal(const sp<IBase>& callback) {
+    if (callback == nullptr) return false;
+
+    bool removed = false;
+    std::lock_guard<std::mutex> _lock(callbacks_lock_);
+    for (auto it = callbacks_.begin(); it != callbacks_.end();) {
+        if (interfacesEqual(*it, callback)) {
+            it = callbacks_.erase(it);
+            removed = true;
+        } else {
+            ++it;
+        }
+    }
+    (void)callback->unlinkToDeath(this).isOk();  // ignore errors
+    return removed;
+}
+
+Return<Result> Health::unregisterCallback(const sp<IHealthInfoCallback>& callback) {
+    return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
+}
+
+template <typename T>
+void getProperty(const std::unique_ptr<BatteryMonitor>& monitor, int id, T defaultValue,
+                 const std::function<void(Result, T)>& callback) {
+    struct BatteryProperty prop;
+    T ret = defaultValue;
+    Result result = Result::SUCCESS;
+    status_t err = monitor->getProperty(static_cast<int>(id), &prop);
+    if (err != OK) {
+        LOG(DEBUG) << "getProperty(" << id << ")"
+                   << " fails: (" << err << ") " << strerror(-err);
+    } else {
+        ret = static_cast<T>(prop.valueInt64);
+    }
+    switch (err) {
+        case OK:
+            result = Result::SUCCESS;
+            break;
+        case NAME_NOT_FOUND:
+            result = Result::NOT_SUPPORTED;
+            break;
+        default:
+            result = Result::UNKNOWN;
+            break;
+    }
+    callback(result, static_cast<T>(ret));
+}
+
+Return<void> Health::getChargeCounter(getChargeCounter_cb _hidl_cb) {
+    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, 0, _hidl_cb);
+    return Void();
+}
+
+Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
+    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CURRENT_NOW, 0, _hidl_cb);
+    return Void();
+}
+
+Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
+    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CURRENT_AVG, 0, _hidl_cb);
+    return Void();
+}
+
+Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
+    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
+    return Void();
+}
+
+Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
+    getProperty<int64_t>(battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, 0, _hidl_cb);
+    return Void();
+}
+
+Return<void> Health::getChargeStatus(getChargeStatus_cb _hidl_cb) {
+    getProperty(battery_monitor_, BATTERY_PROP_BATTERY_STATUS, BatteryStatus::UNKNOWN, _hidl_cb);
+    return Void();
+}
+
+Return<Result> Health::update() {
+    if (!healthd_mode_ops || !healthd_mode_ops->battery_update) {
+        LOG(WARNING) << "health@2.0: update: not initialized. "
+                     << "update() should not be called in charger / recovery.";
+        return Result::UNKNOWN;
+    }
+
+    // Retrieve all information and call healthd_mode_ops->battery_update, which calls
+    // notifyListeners.
+    bool chargerOnline = battery_monitor_->update();
+
+    // adjust uevent / wakealarm periods
+    healthd_battery_update_internal(chargerOnline);
+
+    return Result::SUCCESS;
+}
+
+void Health::notifyListeners(HealthInfo* healthInfo) {
+    std::vector<StorageInfo> info;
+    get_storage_info(info);
+
+    std::vector<DiskStats> stats;
+    get_disk_stats(stats);
+
+    int32_t currentAvg = 0;
+
+    struct BatteryProperty prop;
+    status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
+    if (ret == OK) {
+        currentAvg = static_cast<int32_t>(prop.valueInt64);
+    }
+
+    healthInfo->batteryCurrentAverage = currentAvg;
+    healthInfo->diskStats = stats;
+    healthInfo->storageInfos = info;
+
+    std::lock_guard<std::mutex> _lock(callbacks_lock_);
+    for (auto it = callbacks_.begin(); it != callbacks_.end();) {
+        auto ret = (*it)->healthInfoChanged(*healthInfo);
+        if (!ret.isOk() && ret.isDeadObject()) {
+            it = callbacks_.erase(it);
+        } else {
+            ++it;
+        }
+    }
+}
+
+Return<void> Health::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+    if (handle != nullptr && handle->numFds >= 1) {
+        int fd = handle->data[0];
+        battery_monitor_->dumpState(fd);
+        fsync(fd);
+    }
+    return Void();
+}
+
+Return<void> Health::getStorageInfo(getStorageInfo_cb _hidl_cb) {
+    std::vector<struct StorageInfo> info;
+    get_storage_info(info);
+    hidl_vec<struct StorageInfo> info_vec(info);
+    if (!info.size()) {
+        _hidl_cb(Result::NOT_SUPPORTED, info_vec);
+    } else {
+        _hidl_cb(Result::SUCCESS, info_vec);
+    }
+    return Void();
+}
+
+Return<void> Health::getDiskStats(getDiskStats_cb _hidl_cb) {
+    std::vector<struct DiskStats> stats;
+    get_disk_stats(stats);
+    hidl_vec<struct DiskStats> stats_vec(stats);
+    if (!stats.size()) {
+        _hidl_cb(Result::NOT_SUPPORTED, stats_vec);
+    } else {
+        _hidl_cb(Result::SUCCESS, stats_vec);
+    }
+    return Void();
+}
+
+Return<void> Health::getHealthInfo(getHealthInfo_cb _hidl_cb) {
+    using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+
+    update();
+    struct android::BatteryProperties p = getBatteryProperties(battery_monitor_.get());
+
+    V1_0::HealthInfo batteryInfo;
+    convertToHealthInfo(&p, batteryInfo);
+
+    std::vector<StorageInfo> info;
+    get_storage_info(info);
+
+    std::vector<DiskStats> stats;
+    get_disk_stats(stats);
+
+    int32_t currentAvg = 0;
+
+    struct BatteryProperty prop;
+    status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
+    if (ret == OK) {
+        currentAvg = static_cast<int32_t>(prop.valueInt64);
+    }
+
+    V2_0::HealthInfo healthInfo = {};
+    healthInfo.legacy = std::move(batteryInfo);
+    healthInfo.batteryCurrentAverage = currentAvg;
+    healthInfo.diskStats = stats;
+    healthInfo.storageInfos = info;
+
+    _hidl_cb(Result::SUCCESS, healthInfo);
+    return Void();
+}
+
+void Health::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
+    (void)unregisterCallbackInternal(who.promote());
+}
+
+sp<IHealth> Health::initInstance(struct healthd_config* c) {
+    if (instance_ == nullptr) {
+        instance_ = new Health(c);
+    }
+    return instance_;
+}
+
+sp<Health> Health::getImplementation() {
+    CHECK(instance_ != nullptr);
+    return instance_;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/2.0/default/healthd_common.cpp b/health/2.0/default/healthd_common.cpp
new file mode 100644
index 0000000..8ff409d
--- /dev/null
+++ b/health/2.0/default/healthd_common.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2013 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.health@2.0-impl"
+#define KLOG_LEVEL 6
+
+#include <healthd/BatteryMonitor.h>
+#include <healthd/healthd.h>
+
+#include <batteryservice/BatteryService.h>
+#include <cutils/klog.h>
+#include <cutils/uevent.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <utils/Errors.h>
+
+#include <health2/Health.h>
+
+using namespace android;
+
+// Periodic chores fast interval in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1)
+// Periodic chores fast interval in seconds
+#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10)
+
+static struct healthd_config healthd_config = {
+    .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST,
+    .periodic_chores_interval_slow = DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW,
+    .batteryStatusPath = String8(String8::kEmptyString),
+    .batteryHealthPath = String8(String8::kEmptyString),
+    .batteryPresentPath = String8(String8::kEmptyString),
+    .batteryCapacityPath = String8(String8::kEmptyString),
+    .batteryVoltagePath = String8(String8::kEmptyString),
+    .batteryTemperaturePath = String8(String8::kEmptyString),
+    .batteryTechnologyPath = String8(String8::kEmptyString),
+    .batteryCurrentNowPath = String8(String8::kEmptyString),
+    .batteryCurrentAvgPath = String8(String8::kEmptyString),
+    .batteryChargeCounterPath = String8(String8::kEmptyString),
+    .batteryFullChargePath = String8(String8::kEmptyString),
+    .batteryCycleCountPath = String8(String8::kEmptyString),
+    .energyCounter = NULL,
+    .boot_min_cap = 0,
+    .screen_on = NULL,
+};
+
+static int eventct;
+static int epollfd;
+
+#define POWER_SUPPLY_SUBSYSTEM "power_supply"
+
+// epoll_create() parameter is actually unused
+#define MAX_EPOLL_EVENTS 40
+static int uevent_fd;
+static int wakealarm_fd;
+
+// -1 for no epoll timeout
+static int awake_poll_interval = -1;
+
+static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
+
+using ::android::hardware::health::V2_0::implementation::Health;
+
+struct healthd_mode_ops* healthd_mode_ops = nullptr;
+
+int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
+    struct epoll_event ev;
+
+    ev.events = EPOLLIN;
+
+    if (wakeup == EVENT_WAKEUP_FD) ev.events |= EPOLLWAKEUP;
+
+    ev.data.ptr = (void*)handler;
+    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+        KLOG_ERROR(LOG_TAG, "epoll_ctl failed; errno=%d\n", errno);
+        return -1;
+    }
+
+    eventct++;
+    return 0;
+}
+
+static void wakealarm_set_interval(int interval) {
+    struct itimerspec itval;
+
+    if (wakealarm_fd == -1) return;
+
+    wakealarm_wake_interval = interval;
+
+    if (interval == -1) interval = 0;
+
+    itval.it_interval.tv_sec = interval;
+    itval.it_interval.tv_nsec = 0;
+    itval.it_value.tv_sec = interval;
+    itval.it_value.tv_nsec = 0;
+
+    if (timerfd_settime(wakealarm_fd, 0, &itval, NULL) == -1)
+        KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
+}
+
+void healthd_battery_update_internal(bool charger_online) {
+    // Fast wake interval when on charger (watch for overheat);
+    // slow wake interval when on battery (watch for drained battery).
+
+    int new_wake_interval = charger_online ? healthd_config.periodic_chores_interval_fast
+                                           : healthd_config.periodic_chores_interval_slow;
+
+    if (new_wake_interval != wakealarm_wake_interval) wakealarm_set_interval(new_wake_interval);
+
+    // During awake periods poll at fast rate.  If wake alarm is set at fast
+    // rate then just use the alarm; if wake alarm is set at slow rate then
+    // poll at fast rate while awake and let alarm wake up at slow rate when
+    // asleep.
+
+    if (healthd_config.periodic_chores_interval_fast == -1)
+        awake_poll_interval = -1;
+    else
+        awake_poll_interval = new_wake_interval == healthd_config.periodic_chores_interval_fast
+                                  ? -1
+                                  : healthd_config.periodic_chores_interval_fast * 1000;
+}
+
+static void healthd_battery_update(void) {
+    Health::getImplementation()->update();
+}
+
+static void periodic_chores() {
+    healthd_battery_update();
+}
+
+#define UEVENT_MSG_LEN 2048
+static void uevent_event(uint32_t /*epevents*/) {
+    char msg[UEVENT_MSG_LEN + 2];
+    char* cp;
+    int n;
+
+    n = uevent_kernel_multicast_recv(uevent_fd, msg, UEVENT_MSG_LEN);
+    if (n <= 0) return;
+    if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
+        return;
+
+    msg[n] = '\0';
+    msg[n + 1] = '\0';
+    cp = msg;
+
+    while (*cp) {
+        if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
+            healthd_battery_update();
+            break;
+        }
+
+        /* advance to after the next \0 */
+        while (*cp++)
+            ;
+    }
+}
+
+static void uevent_init(void) {
+    uevent_fd = uevent_open_socket(64 * 1024, true);
+
+    if (uevent_fd < 0) {
+        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+        return;
+    }
+
+    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+    if (healthd_register_event(uevent_fd, uevent_event, EVENT_WAKEUP_FD))
+        KLOG_ERROR(LOG_TAG, "register for uevent events failed\n");
+}
+
+static void wakealarm_event(uint32_t /*epevents*/) {
+    unsigned long long wakeups;
+
+    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
+        return;
+    }
+
+    periodic_chores();
+}
+
+static void wakealarm_init(void) {
+    wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
+    if (wakealarm_fd == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n");
+        return;
+    }
+
+    if (healthd_register_event(wakealarm_fd, wakealarm_event, EVENT_WAKEUP_FD))
+        KLOG_ERROR(LOG_TAG, "Registration of wakealarm event failed\n");
+
+    wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
+}
+
+static void healthd_mainloop(void) {
+    int nevents = 0;
+    while (1) {
+        struct epoll_event events[eventct];
+        int timeout = awake_poll_interval;
+        int mode_timeout;
+
+        /* Don't wait for first timer timeout to run periodic chores */
+        if (!nevents) periodic_chores();
+
+        healthd_mode_ops->heartbeat();
+
+        mode_timeout = healthd_mode_ops->preparetowait();
+        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) timeout = mode_timeout;
+        nevents = epoll_wait(epollfd, events, eventct, timeout);
+        if (nevents == -1) {
+            if (errno == EINTR) continue;
+            KLOG_ERROR(LOG_TAG, "healthd_mainloop: epoll_wait failed\n");
+            break;
+        }
+
+        for (int n = 0; n < nevents; ++n) {
+            if (events[n].data.ptr) (*(void (*)(int))events[n].data.ptr)(events[n].events);
+        }
+    }
+
+    return;
+}
+
+static int healthd_init() {
+    epollfd = epoll_create(MAX_EPOLL_EVENTS);
+    if (epollfd == -1) {
+        KLOG_ERROR(LOG_TAG, "epoll_create failed; errno=%d\n", errno);
+        return -1;
+    }
+
+    healthd_mode_ops->init(&healthd_config);
+    wakealarm_init();
+    uevent_init();
+
+    return 0;
+}
+
+int healthd_main() {
+    int ret;
+
+    klog_set_level(KLOG_LEVEL);
+
+    if (!healthd_mode_ops) {
+        KLOG_ERROR("healthd ops not set, exiting\n");
+        exit(1);
+    }
+
+    ret = healthd_init();
+    if (ret) {
+        KLOG_ERROR("Initialization failed, exiting\n");
+        exit(2);
+    }
+
+    healthd_mainloop();
+    KLOG_ERROR("Main loop terminated, exiting\n");
+    return 3;
+}
diff --git a/health/2.0/default/include/health2/Health.h b/health/2.0/default/include/health2/Health.h
new file mode 100644
index 0000000..134cdc6
--- /dev/null
+++ b/health/2.0/default/include/health2/Health.h
@@ -0,0 +1,77 @@
+#ifndef ANDROID_HARDWARE_HEALTH_V2_0_HEALTH_H
+#define ANDROID_HARDWARE_HEALTH_V2_0_HEALTH_H
+
+#include <memory>
+#include <vector>
+
+#include <android/hardware/health/1.0/types.h>
+#include <android/hardware/health/2.0/IHealth.h>
+#include <healthd/BatteryMonitor.h>
+#include <hidl/Status.h>
+
+using android::hardware::health::V2_0::StorageInfo;
+using android::hardware::health::V2_0::DiskStats;
+
+void get_storage_info(std::vector<struct StorageInfo>& info);
+void get_disk_stats(std::vector<struct DiskStats>& stats);
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+namespace implementation {
+
+using V1_0::BatteryStatus;
+
+using ::android::hidl::base::V1_0::IBase;
+
+struct Health : public IHealth, hidl_death_recipient {
+   public:
+    static sp<IHealth> initInstance(struct healthd_config* c);
+    // Should only be called by implementation itself (-impl, -service).
+    // Clients should not call this function. Instead, initInstance() initializes and returns the
+    // global instance that has fewer functions.
+    // TODO(b/62229583): clean up and hide these functions after update() logic is simplified.
+    static sp<Health> getImplementation();
+
+    Health(struct healthd_config* c);
+
+    // TODO(b/62229583): clean up and hide these functions after update() logic is simplified.
+    void notifyListeners(HealthInfo* info);
+
+    // Methods from IHealth follow.
+    Return<Result> registerCallback(const sp<IHealthInfoCallback>& callback) override;
+    Return<Result> unregisterCallback(const sp<IHealthInfoCallback>& callback) override;
+    Return<Result> update() override;
+    Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
+    Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
+    Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
+    Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
+    Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
+    Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
+    Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
+    Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
+    Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+    void serviceDied(uint64_t cookie, const wp<IBase>& /* who */) override;
+
+   private:
+    static sp<Health> instance_;
+
+    std::mutex callbacks_lock_;
+    std::vector<sp<IHealthInfoCallback>> callbacks_;
+    std::unique_ptr<BatteryMonitor> battery_monitor_;
+
+    bool unregisterCallbackInternal(const sp<IBase>& cb);
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_HEALTH_V2_0_HEALTH_H
diff --git a/health/2.0/types.hal b/health/2.0/types.hal
index 0d17f9f..fe33c88 100644
--- a/health/2.0/types.hal
+++ b/health/2.0/types.hal
@@ -27,39 +27,128 @@
     CALLBACK_DIED,
 };
 
+/*
+ * Identification attributes for a storage device.
+ */
+struct StorageAttribute {
+    /**
+     * Set to true if internal storage
+     */
+    bool isInternal;
+    /**
+     * Set to true if this is the boot device.
+     */
+    bool isBootDevice;
+    /**
+     * Name of the storage device.
+     */
+    string name;
+};
+
+/*
+ * Information on storage device including life time estimates, end of life
+ * information and other attributes.
+ */
+struct StorageInfo {
+    /**
+     * Attributes of the storage device whose info is contained by the struct.
+     */
+    StorageAttribute attr;
+    /**
+     * pre-eol (end of life) information. Follows JEDEC standard No.84-B50.
+     */
+    uint16_t eol;
+    /**
+     * device life time estimation (type A). Follows JEDEC standard No.84-B50.
+     */
+    uint16_t lifetimeA;
+    /**
+     * device life time estimation (type B). Follows JEDEC standard No.84-B50.
+     */
+    uint16_t lifetimeB;
+    /**
+     * version string
+     */
+    string version;
+};
+/*
+ * Disk statistics since boot.
+ */
+struct DiskStats {
+    /**
+     * Number of reads processed.
+     */
+    uint64_t reads;
+    /**
+     * number of read I/Os merged with in-queue I/Os.
+     */
+    uint64_t readMerges;
+    /**
+     * number of sectors read.
+     */
+    uint64_t readSectors;
+    /**
+     * total wait time for read requests.
+     */
+    uint64_t readTicks;
+    /**
+     * number of writes processed.
+     */
+    uint64_t writes;
+    /**
+     * number of writes merged with in-queue I/Os.
+     */
+    uint64_t writeMerges;
+    /**
+     * number of sectors written.
+     */
+    uint64_t writeSectors;
+    /**
+     * total wait time for write requests.
+     */
+    uint64_t writeTicks;
+    /**
+     * number of I/Os currently in flight.
+     */
+    uint64_t ioInFlight;
+    /**
+     * total time this block device has been active.
+     */
+    uint64_t ioTicks;
+    /**
+     * total wait time for all requests.
+     */
+    uint64_t ioInQueue;
+    /**
+     * Attributes of the memory device.
+     */
+    StorageAttribute attr;
+};
+
+/**
+ * Combined Health Information.
+ */
 struct HealthInfo {
     /**
-     * Legacy information from 1.0 HAL.
-     *
-     * If a value is not available, it must be set to 0, UNKNOWN, or empty
-     * string.
+     * V1.0 HealthInfo.
+     * If a member is unsupported, it is filled with:
+     * - 0 (for integers);
+     * - false (for booleans);
+     * - empty string (for strings);
+     * - UNKNOWN (for BatteryStatus and BatteryHealth).
      */
     @1.0::HealthInfo legacy;
-
     /**
-     * Average battery current in microamperes. Positive
-     * values indicate net current entering the battery from a charge source,
-     * negative values indicate net current discharging from the battery.
-     * The time period over which the average is computed may depend on the
-     * fuel gauge hardware and its configuration.
-     *
-     * If this value is not available, it must be set to 0.
+     * Average battery current in uA. Will be 0 if unsupported.
      */
     int32_t batteryCurrentAverage;
-
     /**
-     * Remaining battery capacity percentage of total capacity
-     * (with no fractional part). This value must be in the range 0-100
-     * (inclusive).
-     *
-     * If this value is not available, it must be set to 0.
+     * Disk Statistics. Will be an empty vector if unsupported.
      */
-    int32_t batteryCapacity;
-
+    vec<DiskStats> diskStats;
     /**
-     * Battery remaining energy in nanowatt-hours.
-     *
-     * If this value is not available, it must be set to 0.
+     * Information on storage devices. Will be an empty vector if
+     * unsupported.
      */
-    int64_t energyCounter;
-};
\ No newline at end of file
+    vec<StorageInfo> storageInfos;
+};
diff --git a/health/2.0/utils/libhealthhalutils/Android.bp b/health/2.0/utils/libhealthhalutils/Android.bp
new file mode 100644
index 0000000..5686520
--- /dev/null
+++ b/health/2.0/utils/libhealthhalutils/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Convenience library for (hwbinder) clients to choose the correct health
+// service instance.
+cc_library_static {
+    name: "libhealthhalutils",
+    srcs: ["HealthHalUtils.cpp"],
+    cflags: ["-Wall", "-Werror"],
+    vendor_available: true,
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "android.hardware.health@2.0",
+        "libbase",
+        "libhidlbase",
+    ],
+}
diff --git a/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp b/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
new file mode 100644
index 0000000..9e1cc70
--- /dev/null
+++ b/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HealthHalUtils"
+
+#include <android-base/logging.h>
+#include <healthhalutils/HealthHalUtils.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+
+sp<IHealth> get_health_service() {
+    for (auto&& instanceName : {"default", "backup"}) {
+        auto ret = IHealth::getService(instanceName);
+        if (ret != nullptr) {
+            return ret;
+        }
+        LOG(INFO) << "health: cannot get " << instanceName << " service";
+    }
+    return nullptr;
+}
+
+}  // namespace V2_0
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/2.0/utils/libhealthhalutils/include/healthhalutils/HealthHalUtils.h b/health/2.0/utils/libhealthhalutils/include/healthhalutils/HealthHalUtils.h
new file mode 100644
index 0000000..66acc7c
--- /dev/null
+++ b/health/2.0/utils/libhealthhalutils/include/healthhalutils/HealthHalUtils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HEALTHD_HEALTH_HAL_UTILS_H
+#define HEALTHD_HEALTH_HAL_UTILS_H
+
+#include <android/hardware/health/2.0/IHealth.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+
+// Simplified version of BatteryService.HealthServiceWrapper.init().
+// Returns the "default" health instance when it is available, and "backup" instance
+// otherwise. Before health 1.0 HAL is removed, this function should be used instead
+// of IHealth::getService().
+sp<IHealth> get_health_service();
+
+}  // namespace V2_0
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HEALTHD_HEALTH_HAL_UTILS_H
diff --git a/health/2.0/utils/libhealthservice/Android.bp b/health/2.0/utils/libhealthservice/Android.bp
new file mode 100644
index 0000000..88c38f2
--- /dev/null
+++ b/health/2.0/utils/libhealthservice/Android.bp
@@ -0,0 +1,29 @@
+// Reasonable defaults for android.hardware.health@2.0-service.<device>.
+// Vendor service can customize by implementing functions defined in
+// libhealthd and libhealthstoragedefault.
+
+
+cc_library_static {
+    name: "libhealthservice",
+    vendor_available: true,
+    srcs: ["HealthServiceCommon.cpp"],
+
+    export_include_dirs: ["include"],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "android.hardware.health@2.0",
+    ],
+    static_libs: [
+        "android.hardware.health@2.0-impl",
+        "android.hardware.health@1.0-convert",
+    ],
+    export_static_lib_headers: [
+        "android.hardware.health@1.0-convert",
+    ],
+    header_libs: ["libhealthd_headers"],
+    export_header_lib_headers: ["libhealthd_headers"],
+}
diff --git a/health/2.0/utils/libhealthservice/HealthServiceCommon.cpp b/health/2.0/utils/libhealthservice/HealthServiceCommon.cpp
new file mode 100644
index 0000000..acb4501
--- /dev/null
+++ b/health/2.0/utils/libhealthservice/HealthServiceCommon.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "health@2.0/"
+#include <android-base/logging.h>
+
+#include <android/hardware/health/1.0/types.h>
+#include <hal_conversion.h>
+#include <health2/Health.h>
+#include <health2/service.h>
+#include <healthd/healthd.h>
+#include <hidl/HidlTransportSupport.h>
+
+using android::hardware::IPCThreadState;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::handleTransportPoll;
+using android::hardware::setupTransportPolling;
+using android::hardware::health::V2_0::HealthInfo;
+using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+using android::hardware::health::V2_0::IHealth;
+using android::hardware::health::V2_0::implementation::Health;
+
+extern int healthd_main(void);
+
+static int gBinderFd = -1;
+static std::string gInstanceName;
+
+static void binder_event(uint32_t /*epevents*/) {
+    if (gBinderFd >= 0) handleTransportPoll(gBinderFd);
+}
+
+void healthd_mode_service_2_0_init(struct healthd_config* config) {
+    LOG(INFO) << LOG_TAG << gInstanceName << " Hal is starting up...";
+
+    gBinderFd = setupTransportPolling();
+
+    if (gBinderFd >= 0) {
+        if (healthd_register_event(gBinderFd, binder_event))
+            LOG(ERROR) << LOG_TAG << gInstanceName << ": Register for binder events failed";
+    }
+
+    android::sp<IHealth> service = Health::initInstance(config);
+    CHECK_EQ(service->registerAsService(gInstanceName), android::OK)
+        << LOG_TAG << gInstanceName << ": Failed to register HAL";
+
+    LOG(INFO) << LOG_TAG << gInstanceName << ": Hal init done";
+}
+
+int healthd_mode_service_2_0_preparetowait(void) {
+    IPCThreadState::self()->flushCommands();
+    return -1;
+}
+
+void healthd_mode_service_2_0_heartbeat(void) {
+    // noop
+}
+
+void healthd_mode_service_2_0_battery_update(struct android::BatteryProperties* prop) {
+    HealthInfo info;
+    convertToHealthInfo(prop, info.legacy);
+    Health::getImplementation()->notifyListeners(&info);
+}
+
+static struct healthd_mode_ops healthd_mode_service_2_0_ops = {
+    .init = healthd_mode_service_2_0_init,
+    .preparetowait = healthd_mode_service_2_0_preparetowait,
+    .heartbeat = healthd_mode_service_2_0_heartbeat,
+    .battery_update = healthd_mode_service_2_0_battery_update,
+};
+
+int health_service_main(const char* instance) {
+    gInstanceName = instance;
+    if (gInstanceName.empty()) {
+        gInstanceName = "default";
+    }
+    healthd_mode_ops = &healthd_mode_service_2_0_ops;
+    LOG(INFO) << LOG_TAG << gInstanceName << ": Hal starting main loop...";
+    return healthd_main();
+}
diff --git a/health/2.0/utils/libhealthservice/include/health2/service.h b/health/2.0/utils/libhealthservice/include/health2/service.h
new file mode 100644
index 0000000..d260568
--- /dev/null
+++ b/health/2.0/utils/libhealthservice/include/health2/service.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_HEALTH_V2_0_SERVICE_COMMON
+#define ANDROID_HARDWARE_HEALTH_V2_0_SERVICE_COMMON
+
+int health_service_main(const char* instance = "");
+
+#endif  // ANDROID_HARDWARE_HEALTH_V2_0_SERVICE_COMMON
diff --git a/health/2.0/utils/libhealthstoragedefault/Android.bp b/health/2.0/utils/libhealthstoragedefault/Android.bp
new file mode 100644
index 0000000..cef04fe
--- /dev/null
+++ b/health/2.0/utils/libhealthstoragedefault/Android.bp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Default implementation for (passthrough) clients that statically links to
+// android.hardware.health@2.0-impl but do no query for storage related
+// information.
+cc_library_static {
+    srcs: ["StorageHealthDefault.cpp"],
+    name: "libhealthstoragedefault",
+    vendor_available: true,
+    cflags: ["-Werror"],
+    shared_libs: [
+        "android.hardware.health@2.0",
+    ],
+}
diff --git a/health/2.0/utils/libhealthstoragedefault/StorageHealthDefault.cpp b/health/2.0/utils/libhealthstoragedefault/StorageHealthDefault.cpp
new file mode 100644
index 0000000..aba6cc3
--- /dev/null
+++ b/health/2.0/utils/libhealthstoragedefault/StorageHealthDefault.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "include/StorageHealthDefault.h"
+
+void get_storage_info(std::vector<struct StorageInfo>&) {
+    // Use defaults.
+}
+
+void get_disk_stats(std::vector<struct DiskStats>&) {
+    // Use defaults
+}
diff --git a/health/2.0/utils/libhealthstoragedefault/include/StorageHealthDefault.h b/health/2.0/utils/libhealthstoragedefault/include/StorageHealthDefault.h
new file mode 100644
index 0000000..85eb210
--- /dev/null
+++ b/health/2.0/utils/libhealthstoragedefault/include/StorageHealthDefault.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_HEALTH_V2_0_STORAGE_HEALTH_H
+#define ANDROID_HARDWARE_HEALTH_V2_0_STORAGE_HEALTH_H
+
+#include <android/hardware/health/2.0/types.h>
+
+using android::hardware::health::V2_0::StorageInfo;
+using android::hardware::health::V2_0::DiskStats;
+
+/*
+ * Get storage information.
+ */
+void get_storage_info(std::vector<struct StorageInfo>& info);
+
+/*
+ * Get disk statistics.
+ */
+void get_disk_stats(std::vector<struct DiskStats>& stats);
+
+#endif  // ANDROID_HARDWARE_HEALTH_V2_0_STORAGE_HEALTH_H
diff --git a/health/2.0/vts/functional/Android.bp b/health/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..4ad01b9
--- /dev/null
+++ b/health/2.0/vts/functional/Android.bp
@@ -0,0 +1,25 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalHealthV2_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalHealthV2_0TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.health@1.0",
+        "android.hardware.health@2.0",
+    ],
+}
diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
new file mode 100644
index 0000000..972bc7f
--- /dev/null
+++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "health_hidl_hal_test"
+
+#include <mutex>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/health/2.0/IHealth.h>
+#include <android/hardware/health/2.0/types.h>
+
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
+using ::testing::VtsHalHidlTargetTestBase;
+using ::testing::VtsHalHidlTargetTestEnvBase;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+
+using V1_0::BatteryStatus;
+
+// Test environment for graphics.composer
+class HealthHidlEnvironment : public VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static HealthHidlEnvironment* Instance() {
+        static HealthHidlEnvironment* instance = new HealthHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IHealth>(); }
+
+   private:
+    HealthHidlEnvironment() {}
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(HealthHidlEnvironment);
+};
+
+class HealthHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        std::string serviceName = HealthHidlEnvironment::Instance()->getServiceName<IHealth>();
+        LOG(INFO) << "get service with name:" << serviceName;
+        ASSERT_FALSE(serviceName.empty());
+        mHealth = ::testing::VtsHalHidlTargetTestBase::getService<IHealth>(serviceName);
+        ASSERT_NE(mHealth, nullptr);
+    }
+
+    sp<IHealth> mHealth;
+};
+
+class Callback : public IHealthInfoCallback {
+   public:
+    Return<void> healthInfoChanged(const HealthInfo&) override {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mInvoked = true;
+        mInvokedNotify.notify_all();
+        return Void();
+    }
+    template <typename R, typename P>
+    bool waitInvoke(std::chrono::duration<R, P> duration) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        bool r = mInvokedNotify.wait_for(lock, duration, [this] { return this->mInvoked; });
+        mInvoked = false;
+        return r;
+    }
+   private:
+    std::mutex mMutex;
+    std::condition_variable mInvokedNotify;
+    bool mInvoked = false;
+};
+
+#define ASSERT_OK(r) ASSERT_TRUE(isOk(r))
+#define EXPECT_OK(r) EXPECT_TRUE(isOk(r))
+template <typename T>
+AssertionResult isOk(const Return<T>& r) {
+    return r.isOk() ? AssertionSuccess() : (AssertionFailure() << r.description());
+}
+
+#define ASSERT_ALL_OK(r) ASSERT_TRUE(isAllOk(r))
+// Both isOk() and Result::SUCCESS
+AssertionResult isAllOk(const Return<Result>& r) {
+    if (!r.isOk()) {
+        return AssertionFailure() << r.description();
+    }
+    if (static_cast<Result>(r) != Result::SUCCESS) {
+        return AssertionFailure() << toString(static_cast<Result>(r));
+    }
+    return AssertionSuccess();
+}
+
+/**
+ * Test whether callbacks work. Tested functions are IHealth::registerCallback,
+ * unregisterCallback, and update.
+ */
+TEST_F(HealthHidlTest, Callbacks) {
+    using namespace std::chrono_literals;
+    sp<Callback> firstCallback = new Callback();
+    sp<Callback> secondCallback = new Callback();
+
+    ASSERT_ALL_OK(mHealth->registerCallback(firstCallback));
+    ASSERT_ALL_OK(mHealth->registerCallback(secondCallback));
+
+    // registerCallback may or may not invoke the callback immediately, so the test needs
+    // to wait for the invocation. If the implementation chooses not to invoke the callback
+    // immediately, just wait for some time.
+    firstCallback->waitInvoke(200ms);
+    secondCallback->waitInvoke(200ms);
+
+    // assert that the first callback is invoked when update is called.
+    ASSERT_ALL_OK(mHealth->update());
+
+    ASSERT_TRUE(firstCallback->waitInvoke(1s));
+    ASSERT_TRUE(secondCallback->waitInvoke(1s));
+
+    ASSERT_ALL_OK(mHealth->unregisterCallback(firstCallback));
+
+    // clear any potentially pending callbacks result from wakealarm / kernel events
+    // If there is none, just wait for some time.
+    firstCallback->waitInvoke(200ms);
+    secondCallback->waitInvoke(200ms);
+
+    // assert that the second callback is still invoked even though the first is unregistered.
+    ASSERT_ALL_OK(mHealth->update());
+
+    ASSERT_FALSE(firstCallback->waitInvoke(200ms));
+    ASSERT_TRUE(secondCallback->waitInvoke(1s));
+
+    ASSERT_ALL_OK(mHealth->unregisterCallback(secondCallback));
+}
+
+TEST_F(HealthHidlTest, UnregisterNonExistentCallback) {
+    sp<Callback> callback = new Callback();
+    auto ret = mHealth->unregisterCallback(callback);
+    ASSERT_OK(ret);
+    ASSERT_EQ(Result::NOT_FOUND, static_cast<Result>(ret)) << "Actual: " << toString(ret);
+}
+
+/**
+ * Pass the test if:
+ *  - Property is not supported (res == NOT_SUPPORTED)
+ *  - Result is success, and predicate is true
+ * @param res the Result value.
+ * @param valueStr the string representation for actual value (for error message)
+ * @param pred a predicate that test whether the value is valid
+ */
+#define EXPECT_VALID_OR_UNSUPPORTED_PROP(res, valueStr, pred) \
+    EXPECT_TRUE(isPropertyOk(res, valueStr, pred, #pred))
+
+AssertionResult isPropertyOk(Result res, const std::string& valueStr, bool pred,
+                             const std::string& predStr) {
+    if (res == Result::SUCCESS) {
+        if (pred) {
+            return AssertionSuccess();
+        }
+        return AssertionFailure() << "value doesn't match.\nActual: " << valueStr
+                                  << "\nExpected: " << predStr;
+    }
+    if (res == Result::NOT_SUPPORTED) {
+        return AssertionSuccess();
+    }
+    return AssertionFailure() << "Result is not SUCCESS or NOT_SUPPORTED: " << toString(res);
+}
+
+bool verifyStorageInfo(const hidl_vec<struct StorageInfo>& info) {
+    for (size_t i = 0; i < info.size(); i++) {
+        if (!(0 <= info[i].eol && info[i].eol <= 3 && 0 <= info[i].lifetimeA &&
+              info[i].lifetimeA <= 0x0B && 0 <= info[i].lifetimeB && info[i].lifetimeB <= 0x0B)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool verifyDiskStats(const hidl_vec<struct DiskStats>& stats) {
+    for (size_t i = 0; i < stats.size(); i++) {
+        if (!(stats[i].reads > 0 && stats[i].readMerges > 0 && stats[i].readSectors > 0 &&
+              stats[i].readTicks > 0 && stats[i].writes > 0 && stats[i].writeMerges > 0 &&
+              stats[i].writeSectors > 0 && stats[i].writeTicks > 0 && stats[i].ioTicks > 0)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+template <typename T>
+bool verifyEnum(T value) {
+    for (auto it : hidl_enum_iterator<T>()) {
+        if (it == value) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool verifyHealthInfo(const HealthInfo& health_info) {
+    if (!verifyStorageInfo(health_info.storageInfos) || !verifyDiskStats(health_info.diskStats)) {
+        return false;
+    }
+
+    using V1_0::BatteryStatus;
+    using V1_0::BatteryHealth;
+
+    if (!((health_info.legacy.batteryChargeCounter > 0) &&
+          (health_info.legacy.batteryCurrent != INT32_MIN) &&
+          (0 <= health_info.legacy.batteryLevel && health_info.legacy.batteryLevel <= 100) &&
+          verifyEnum<BatteryHealth>(health_info.legacy.batteryHealth) &&
+          (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN) &&
+          verifyEnum<BatteryStatus>(health_info.legacy.batteryStatus))) {
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Tests the values returned by getChargeCounter(),
+ * getCurrentNow(), getCurrentAverage(), getCapacity(), getEnergyCounter(),
+ * getChargeStatus(), getStorageInfo(), getDiskStats() and getHealthInfo() from
+ * interface IHealth.
+ */
+TEST_F(HealthHidlTest, Properties) {
+    EXPECT_OK(mHealth->getChargeCounter([](auto result, auto value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value > 0);
+    }));
+    EXPECT_OK(mHealth->getCurrentNow([](auto result, auto value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN);
+    }));
+    EXPECT_OK(mHealth->getCurrentAverage([](auto result, auto value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT32_MIN);
+    }));
+    EXPECT_OK(mHealth->getCapacity([](auto result, auto value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), 0 <= value && value <= 100);
+    }));
+    EXPECT_OK(mHealth->getEnergyCounter([](auto result, auto value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value != INT64_MIN);
+    }));
+    EXPECT_OK(mHealth->getChargeStatus([](auto result, auto value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(
+            result, toString(value),
+            value != BatteryStatus::UNKNOWN && verifyEnum<BatteryStatus>(value));
+    }));
+    EXPECT_OK(mHealth->getStorageInfo([](auto result, auto& value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyStorageInfo(value));
+    }));
+    EXPECT_OK(mHealth->getDiskStats([](auto result, auto& value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyDiskStats(value));
+    }));
+    EXPECT_OK(mHealth->getHealthInfo([](auto result, auto& value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyHealthInfo(value));
+    }));
+}
+
+}  // namespace V2_0
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    using ::android::hardware::health::V2_0::HealthHidlEnvironment;
+    ::testing::AddGlobalTestEnvironment(HealthHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    HealthHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/ir/1.0/default/android.hardware.ir@1.0-service.rc b/ir/1.0/default/android.hardware.ir@1.0-service.rc
index 47f34fe..0d06967 100644
--- a/ir/1.0/default/android.hardware.ir@1.0-service.rc
+++ b/ir/1.0/default/android.hardware.ir@1.0-service.rc
@@ -1,4 +1,4 @@
-service ir-hal-1-0 /vendor/bin/hw/android.hardware.ir@1.0-service
+service vendor.ir-hal-1-0 /vendor/bin/hw/android.hardware.ir@1.0-service
     class hal
     user system
-    group system
\ No newline at end of file
+    group system
diff --git a/keymaster/3.0/default/Android.mk b/keymaster/3.0/default/Android.mk
index 87ad245..9e7d04a 100644
--- a/keymaster/3.0/default/Android.mk
+++ b/keymaster/3.0/default/Android.mk
@@ -12,7 +12,8 @@
     libsoftkeymasterdevice \
     libcrypto \
     libkeymaster_portable \
-    libkeymaster_staging \
+    libpuresoftkeymasterdevice \
+    libkeymaster3device \
     libhidlbase \
     libhidltransport \
     libutils \
diff --git a/keymaster/3.0/default/KeymasterDevice.cpp b/keymaster/3.0/default/KeymasterDevice.cpp
index d83963f..6fabbde 100644
--- a/keymaster/3.0/default/KeymasterDevice.cpp
+++ b/keymaster/3.0/default/KeymasterDevice.cpp
@@ -21,9 +21,11 @@
 
 #include <cutils/log.h>
 
+#include <AndroidKeymaster3Device.h>
+#include <hardware/keymaster0.h>
+#include <hardware/keymaster1.h>
+#include <hardware/keymaster2.h>
 #include <hardware/keymaster_defs.h>
-#include <keymaster/keymaster_configuration.h>
-#include <keymaster/soft_keymaster_device.h>
 
 namespace android {
 namespace hardware {
@@ -31,717 +33,77 @@
 namespace V3_0 {
 namespace implementation {
 
-using ::keymaster::SoftKeymasterDevice;
-
-class SoftwareOnlyHidlKeymasterEnforcement : public ::keymaster::KeymasterEnforcement {
-  public:
-    SoftwareOnlyHidlKeymasterEnforcement() : KeymasterEnforcement(64, 64) {}
-
-    uint32_t get_current_time() const override {
-        struct timespec tp;
-        int err = clock_gettime(CLOCK_MONOTONIC, &tp);
-        if (err || tp.tv_sec < 0) return 0;
-        return static_cast<uint32_t>(tp.tv_sec);
-    }
-
-    bool activation_date_valid(uint64_t) const override { return true; }
-    bool expiration_date_passed(uint64_t) const override { return false; }
-    bool auth_token_timed_out(const hw_auth_token_t&, uint32_t) const override { return false; }
-    bool ValidateTokenSignature(const hw_auth_token_t&) const override { return true; }
-};
-
-class SoftwareOnlyHidlKeymasterContext : public ::keymaster::SoftKeymasterContext {
-  public:
-    SoftwareOnlyHidlKeymasterContext() : enforcement_(new SoftwareOnlyHidlKeymasterEnforcement) {}
-
-    ::keymaster::KeymasterEnforcement* enforcement_policy() override { return enforcement_.get(); }
-
-  private:
-    std::unique_ptr<::keymaster::KeymasterEnforcement> enforcement_;
-};
-
-static int keymaster0_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) {
-    assert(mod->module_api_version < KEYMASTER_MODULE_API_VERSION_1_0);
-    ALOGI("Found keymaster0 module %s, version %x", mod->name, mod->module_api_version);
-
-    std::unique_ptr<SoftKeymasterDevice> soft_keymaster(new SoftKeymasterDevice);
-    keymaster0_device_t* km0_device = NULL;
-    keymaster_error_t error = KM_ERROR_OK;
-
-    int rc = keymaster0_open(mod, &km0_device);
+static int get_keymaster0_dev(keymaster0_device_t** dev, const hw_module_t* mod) {
+    int rc = keymaster0_open(mod, dev);
     if (rc) {
         ALOGE("Error opening keystore keymaster0 device.");
-        goto err;
+        *dev = nullptr;
+        return rc;
     }
-
-    if (km0_device->flags & KEYMASTER_SOFTWARE_ONLY) {
-        ALOGI("Keymaster0 module is software-only.  Using SoftKeymasterDevice instead.");
-        km0_device->common.close(&km0_device->common);
-        km0_device = NULL;
-        // SoftKeymasterDevice will be deleted by keymaster_device_release()
-        *dev = soft_keymaster.release()->keymaster2_device();
-        return 0;
-    }
-
-    ALOGD("Wrapping keymaster0 module %s with SoftKeymasterDevice", mod->name);
-    error = soft_keymaster->SetHardwareDevice(km0_device);
-    km0_device = NULL;  // SoftKeymasterDevice has taken ownership.
-    if (error != KM_ERROR_OK) {
-        ALOGE("Got error %d from SetHardwareDevice", error);
-        rc = error;
-        goto err;
-    }
-
-    // SoftKeymasterDevice will be deleted by  keymaster_device_release()
-    *dev = soft_keymaster.release()->keymaster2_device();
     return 0;
-
-err:
-    if (km0_device) km0_device->common.close(&km0_device->common);
-    *dev = NULL;
-    return rc;
 }
 
-static int keymaster1_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev,
-                                        bool* supports_all_digests) {
-    assert(mod->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0);
-    ALOGI("Found keymaster1 module %s, version %x", mod->name, mod->module_api_version);
-
-    std::unique_ptr<SoftKeymasterDevice> soft_keymaster(new SoftKeymasterDevice);
-    keymaster1_device_t* km1_device = nullptr;
-    keymaster_error_t error = KM_ERROR_OK;
-
-    int rc = keymaster1_open(mod, &km1_device);
+static int get_keymaster1_dev(keymaster1_device_t** dev, const hw_module_t* mod) {
+    int rc = keymaster1_open(mod, dev);
     if (rc) {
         ALOGE("Error %d opening keystore keymaster1 device", rc);
-        goto err;
+        if (*dev) {
+            (*dev)->common.close(&(*dev)->common);
+            *dev = nullptr;
+        }
     }
-
-    ALOGD("Wrapping keymaster1 module %s with SofKeymasterDevice", mod->name);
-    error = soft_keymaster->SetHardwareDevice(km1_device);
-    km1_device = nullptr;  // SoftKeymasterDevice has taken ownership.
-    if (error != KM_ERROR_OK) {
-        ALOGE("Got error %d from SetHardwareDevice", error);
-        rc = error;
-        goto err;
-    }
-
-    // SoftKeymasterDevice will be deleted by keymaster_device_release()
-    *supports_all_digests = soft_keymaster->supports_all_digests();
-    *dev = soft_keymaster.release()->keymaster2_device();
-    return 0;
-
-err:
-    if (km1_device) km1_device->common.close(&km1_device->common);
-    *dev = NULL;
     return rc;
 }
 
-static int keymaster2_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) {
-    assert(mod->module_api_version >= KEYMASTER_MODULE_API_VERSION_2_0);
-    ALOGI("Found keymaster2 module %s, version %x", mod->name, mod->module_api_version);
-
-    keymaster2_device_t* km2_device = nullptr;
-
-    int rc = keymaster2_open(mod, &km2_device);
+static int get_keymaster2_dev(keymaster2_device_t** dev, const hw_module_t* mod) {
+    int rc = keymaster2_open(mod, dev);
     if (rc) {
         ALOGE("Error %d opening keystore keymaster2 device", rc);
-        goto err;
+        *dev = nullptr;
     }
-
-    *dev = km2_device;
-    return 0;
-
-err:
-    if (km2_device) km2_device->common.close(&km2_device->common);
-    *dev = nullptr;
     return rc;
 }
 
-static int keymaster_device_initialize(keymaster2_device_t** dev, uint32_t* version,
-                                       bool* supports_ec, bool* supports_all_digests) {
-    const hw_module_t* mod;
-
-    *supports_ec = true;
+static IKeymasterDevice* createKeymaster3Device() {
+    const hw_module_t* mod = nullptr;
 
     int rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod);
     if (rc) {
         ALOGI("Could not find any keystore module, using software-only implementation.");
         // SoftKeymasterDevice will be deleted by keymaster_device_release()
-        *dev = (new SoftKeymasterDevice(new SoftwareOnlyHidlKeymasterContext))->keymaster2_device();
-        *version = -1;
-        return 0;
+        return ::keymaster::ng::CreateKeymasterDevice();
     }
 
     if (mod->module_api_version < KEYMASTER_MODULE_API_VERSION_1_0) {
-        *version = 0;
-        *supports_all_digests = false;
-        int rc = keymaster0_device_initialize(mod, dev);
-        if (rc == 0 && ((*dev)->flags & KEYMASTER_SUPPORTS_EC) == 0) {
-            *supports_ec = false;
+        keymaster0_device_t* dev = nullptr;
+        if (get_keymaster0_dev(&dev, mod)) {
+            return nullptr;
         }
-        return rc;
+        return ::keymaster::ng::CreateKeymasterDevice(dev);
     } else if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) {
-        *version = 1;
-        return keymaster1_device_initialize(mod, dev, supports_all_digests);
+        keymaster1_device_t* dev = nullptr;
+        if (get_keymaster1_dev(&dev, mod)) {
+            return nullptr;
+        }
+        return ::keymaster::ng::CreateKeymasterDevice(dev);
     } else {
-        *version = 2;
-        *supports_all_digests = true;
-        return keymaster2_device_initialize(mod, dev);
-    }
-}
-
-KeymasterDevice::~KeymasterDevice() {
-    if (keymaster_device_) keymaster_device_->common.close(&keymaster_device_->common);
-}
-
-static inline keymaster_tag_type_t typeFromTag(const keymaster_tag_t tag) {
-    return keymaster_tag_get_type(tag);
-}
-
-/**
- * legacy_enum_conversion converts enums from hidl to keymaster and back. Currently, this is just a
- * cast to make the compiler happy. One of two thigs should happen though:
- * TODO The keymaster enums should become aliases for the hidl generated enums so that we have a
- *      single point of truth. Then this cast function can go away.
- */
-inline static keymaster_tag_t legacy_enum_conversion(const Tag value) {
-    return keymaster_tag_t(value);
-}
-inline static Tag legacy_enum_conversion(const keymaster_tag_t value) {
-    return Tag(value);
-}
-inline static keymaster_purpose_t legacy_enum_conversion(const KeyPurpose value) {
-    return keymaster_purpose_t(value);
-}
-inline static keymaster_key_format_t legacy_enum_conversion(const KeyFormat value) {
-    return keymaster_key_format_t(value);
-}
-inline static ErrorCode legacy_enum_conversion(const keymaster_error_t value) {
-    return ErrorCode(value);
-}
-
-class KmParamSet : public keymaster_key_param_set_t {
-  public:
-    KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
-        params = new keymaster_key_param_t[keyParams.size()];
-        length = keyParams.size();
-        for (size_t i = 0; i < keyParams.size(); ++i) {
-            auto tag = legacy_enum_conversion(keyParams[i].tag);
-            switch (typeFromTag(tag)) {
-            case KM_ENUM:
-            case KM_ENUM_REP:
-                params[i] = keymaster_param_enum(tag, keyParams[i].f.integer);
-                break;
-            case KM_UINT:
-            case KM_UINT_REP:
-                params[i] = keymaster_param_int(tag, keyParams[i].f.integer);
-                break;
-            case KM_ULONG:
-            case KM_ULONG_REP:
-                params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger);
-                break;
-            case KM_DATE:
-                params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime);
-                break;
-            case KM_BOOL:
-                if (keyParams[i].f.boolValue)
-                    params[i] = keymaster_param_bool(tag);
-                else
-                    params[i].tag = KM_TAG_INVALID;
-                break;
-            case KM_BIGNUM:
-            case KM_BYTES:
-                params[i] =
-                    keymaster_param_blob(tag, &keyParams[i].blob[0], keyParams[i].blob.size());
-                break;
-            case KM_INVALID:
-            default:
-                params[i].tag = KM_TAG_INVALID;
-                /* just skip */
-                break;
-            }
+        keymaster2_device_t* dev = nullptr;
+        if (get_keymaster2_dev(&dev, mod)) {
+            return nullptr;
         }
+        return ::keymaster::ng::CreateKeymasterDevice(dev);
     }
-    KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} {
-        other.length = 0;
-        other.params = nullptr;
-    }
-    KmParamSet(const KmParamSet&) = delete;
-    ~KmParamSet() { delete[] params; }
-};
-
-inline static KmParamSet hidlParams2KmParamSet(const hidl_vec<KeyParameter>& params) {
-    return KmParamSet(params);
-}
-
-inline static keymaster_blob_t hidlVec2KmBlob(const hidl_vec<uint8_t>& blob) {
-    /* hidl unmarshals funny pointers if the the blob is empty */
-    if (blob.size()) return {&blob[0], blob.size()};
-    return {nullptr, 0};
-}
-
-inline static keymaster_key_blob_t hidlVec2KmKeyBlob(const hidl_vec<uint8_t>& blob) {
-    /* hidl unmarshals funny pointers if the the blob is empty */
-    if (blob.size()) return {&blob[0], blob.size()};
-    return {nullptr, 0};
-}
-
-inline static hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_key_blob_t& blob) {
-    hidl_vec<uint8_t> result;
-    result.setToExternal(const_cast<unsigned char*>(blob.key_material), blob.key_material_size);
-    return result;
-}
-inline static hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_blob_t& blob) {
-    hidl_vec<uint8_t> result;
-    result.setToExternal(const_cast<unsigned char*>(blob.data), blob.data_length);
-    return result;
-}
-
-inline static hidl_vec<hidl_vec<uint8_t>>
-kmCertChain2Hidl(const keymaster_cert_chain_t* cert_chain) {
-    hidl_vec<hidl_vec<uint8_t>> result;
-    if (!cert_chain || cert_chain->entry_count == 0 || !cert_chain->entries) return result;
-
-    result.resize(cert_chain->entry_count);
-    for (size_t i = 0; i < cert_chain->entry_count; ++i) {
-        auto& entry = cert_chain->entries[i];
-        result[i] = kmBlob2hidlVec(entry);
-    }
-
-    return result;
-}
-
-static inline hidl_vec<KeyParameter> kmParamSet2Hidl(const keymaster_key_param_set_t& set) {
-    hidl_vec<KeyParameter> result;
-    if (set.length == 0 || set.params == nullptr) return result;
-
-    result.resize(set.length);
-    keymaster_key_param_t* params = set.params;
-    for (size_t i = 0; i < set.length; ++i) {
-        auto tag = params[i].tag;
-        result[i].tag = legacy_enum_conversion(tag);
-        switch (typeFromTag(tag)) {
-        case KM_ENUM:
-        case KM_ENUM_REP:
-            result[i].f.integer = params[i].enumerated;
-            break;
-        case KM_UINT:
-        case KM_UINT_REP:
-            result[i].f.integer = params[i].integer;
-            break;
-        case KM_ULONG:
-        case KM_ULONG_REP:
-            result[i].f.longInteger = params[i].long_integer;
-            break;
-        case KM_DATE:
-            result[i].f.dateTime = params[i].date_time;
-            break;
-        case KM_BOOL:
-            result[i].f.boolValue = params[i].boolean;
-            break;
-        case KM_BIGNUM:
-        case KM_BYTES:
-            result[i].blob.setToExternal(const_cast<unsigned char*>(params[i].blob.data),
-                                         params[i].blob.data_length);
-            break;
-        case KM_INVALID:
-        default:
-            params[i].tag = KM_TAG_INVALID;
-            /* just skip */
-            break;
-        }
-    }
-    return result;
-}
-
-// Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow.
-Return<void> KeymasterDevice::getHardwareFeatures(getHardwareFeatures_cb _hidl_cb) {
-    bool is_secure = !(keymaster_device_->flags & KEYMASTER_SOFTWARE_ONLY);
-    bool supports_symmetric_cryptography = false;
-    bool supports_attestation = false;
-
-    switch (hardware_version_) {
-    case 2:
-        supports_attestation = true;
-    /* Falls through */
-    case 1:
-        supports_symmetric_cryptography = true;
-        break;
-    };
-
-    _hidl_cb(is_secure, hardware_supports_ec_, supports_symmetric_cryptography,
-             supports_attestation, hardware_supports_all_digests_,
-             keymaster_device_->common.module->name, keymaster_device_->common.module->author);
-    return Void();
-}
-
-Return<ErrorCode> KeymasterDevice::addRngEntropy(const hidl_vec<uint8_t>& data) {
-    if (!data.size()) return ErrorCode::OK;
-    return legacy_enum_conversion(
-        keymaster_device_->add_rng_entropy(keymaster_device_, &data[0], data.size()));
-}
-
-Return<void> KeymasterDevice::generateKey(const hidl_vec<KeyParameter>& keyParams,
-                                          generateKey_cb _hidl_cb) {
-    // result variables for the wire
-    KeyCharacteristics resultCharacteristics;
-    hidl_vec<uint8_t> resultKeyBlob;
-
-    // result variables the backend understands
-    keymaster_key_blob_t key_blob{nullptr, 0};
-    keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}};
-
-    // convert the parameter set to something our backend understands
-    auto kmParams = hidlParams2KmParamSet(keyParams);
-
-    auto rc = keymaster_device_->generate_key(keymaster_device_, &kmParams, &key_blob,
-                                              &key_characteristics);
-
-    if (rc == KM_ERROR_OK) {
-        // on success convert the result to wire format
-        resultKeyBlob = kmBlob2hidlVec(key_blob);
-        resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced);
-        resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced);
-    }
-
-    // send results off to the client
-    _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob, resultCharacteristics);
-
-    // free buffers that we are responsible for
-    if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material));
-    keymaster_free_characteristics(&key_characteristics);
-
-    return Void();
-}
-
-Return<void> KeymasterDevice::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
-                                                    const hidl_vec<uint8_t>& clientId,
-                                                    const hidl_vec<uint8_t>& appData,
-                                                    getKeyCharacteristics_cb _hidl_cb) {
-    // result variables for the wire
-    KeyCharacteristics resultCharacteristics;
-
-    // result variables the backend understands
-    keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}};
-
-    auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob);
-    auto kmClientId = hidlVec2KmBlob(clientId);
-    auto kmAppData = hidlVec2KmBlob(appData);
-
-    auto rc = keymaster_device_->get_key_characteristics(
-        keymaster_device_, keyBlob.size() ? &kmKeyBlob : nullptr,
-        clientId.size() ? &kmClientId : nullptr, appData.size() ? &kmAppData : nullptr,
-        &key_characteristics);
-
-    if (rc == KM_ERROR_OK) {
-        resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced);
-        resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced);
-    }
-
-    _hidl_cb(legacy_enum_conversion(rc), resultCharacteristics);
-
-    keymaster_free_characteristics(&key_characteristics);
-
-    return Void();
-}
-
-Return<void> KeymasterDevice::importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
-                                        const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) {
-    // result variables for the wire
-    KeyCharacteristics resultCharacteristics;
-    hidl_vec<uint8_t> resultKeyBlob;
-
-    // result variables the backend understands
-    keymaster_key_blob_t key_blob{nullptr, 0};
-    keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}};
-
-    auto kmParams = hidlParams2KmParamSet(params);
-    auto kmKeyData = hidlVec2KmBlob(keyData);
-
-    auto rc = keymaster_device_->import_key(keymaster_device_, &kmParams,
-                                            legacy_enum_conversion(keyFormat), &kmKeyData,
-                                            &key_blob, &key_characteristics);
-
-    if (rc == KM_ERROR_OK) {
-        // on success convert the result to wire format
-        // (Can we assume that key_blob is {nullptr, 0} or a valid buffer description?)
-        resultKeyBlob = kmBlob2hidlVec(key_blob);
-        resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced);
-        resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced);
-    }
-
-    _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob, resultCharacteristics);
-
-    // free buffers that we are responsible for
-    if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material));
-    keymaster_free_characteristics(&key_characteristics);
-
-    return Void();
-}
-
-Return<void> KeymasterDevice::exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
-                                        const hidl_vec<uint8_t>& clientId,
-                                        const hidl_vec<uint8_t>& appData, exportKey_cb _hidl_cb) {
-
-    // result variables for the wire
-    hidl_vec<uint8_t> resultKeyBlob;
-
-    // result variables the backend understands
-    keymaster_blob_t out_blob{nullptr, 0};
-
-    auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob);
-    auto kmClientId = hidlVec2KmBlob(clientId);
-    auto kmAppData = hidlVec2KmBlob(appData);
-
-    auto rc = keymaster_device_->export_key(keymaster_device_, legacy_enum_conversion(exportFormat),
-                                            keyBlob.size() ? &kmKeyBlob : nullptr,
-                                            clientId.size() ? &kmClientId : nullptr,
-                                            appData.size() ? &kmAppData : nullptr, &out_blob);
-
-    if (rc == KM_ERROR_OK) {
-        // on success convert the result to wire format
-        // (Can we assume that key_blob is {nullptr, 0} or a valid buffer description?)
-        resultKeyBlob = kmBlob2hidlVec(out_blob);
-    }
-
-    _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob);
-
-    // free buffers that we are responsible for
-    if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data));
-
-    return Void();
-}
-
-Return<void> KeymasterDevice::attestKey(const hidl_vec<uint8_t>& keyToAttest,
-                                        const hidl_vec<KeyParameter>& attestParams,
-                                        attestKey_cb _hidl_cb) {
-
-    hidl_vec<hidl_vec<uint8_t>> resultCertChain;
-
-    bool foundAttestationApplicationId = false;
-    for (size_t i = 0; i < attestParams.size(); ++i) {
-        switch (attestParams[i].tag) {
-        case Tag::ATTESTATION_ID_BRAND:
-        case Tag::ATTESTATION_ID_DEVICE:
-        case Tag::ATTESTATION_ID_PRODUCT:
-        case Tag::ATTESTATION_ID_SERIAL:
-        case Tag::ATTESTATION_ID_IMEI:
-        case Tag::ATTESTATION_ID_MEID:
-        case Tag::ATTESTATION_ID_MANUFACTURER:
-        case Tag::ATTESTATION_ID_MODEL:
-            // Device id attestation may only be supported if the device is able to permanently
-            // destroy its knowledge of the ids. This device is unable to do this, so it must
-            // never perform any device id attestation.
-            _hidl_cb(ErrorCode::CANNOT_ATTEST_IDS, resultCertChain);
-            return Void();
-
-        case Tag::ATTESTATION_APPLICATION_ID:
-            foundAttestationApplicationId = true;
-            break;
-
-        default:
-            break;
-        }
-    }
-
-    // KM3 devices reject missing attest application IDs. KM2 devices do not.
-    if (!foundAttestationApplicationId) {
-        _hidl_cb(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
-                 resultCertChain);
-        return Void();
-    }
-
-    keymaster_cert_chain_t cert_chain{nullptr, 0};
-
-    auto kmKeyToAttest = hidlVec2KmKeyBlob(keyToAttest);
-    auto kmAttestParams = hidlParams2KmParamSet(attestParams);
-
-    auto rc = keymaster_device_->attest_key(keymaster_device_, &kmKeyToAttest, &kmAttestParams,
-                                            &cert_chain);
-
-    if (rc == KM_ERROR_OK) {
-        resultCertChain = kmCertChain2Hidl(&cert_chain);
-    }
-
-    _hidl_cb(legacy_enum_conversion(rc), resultCertChain);
-
-    keymaster_free_cert_chain(&cert_chain);
-
-    return Void();
-}
-
-Return<void> KeymasterDevice::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
-                                         const hidl_vec<KeyParameter>& upgradeParams,
-                                         upgradeKey_cb _hidl_cb) {
-
-    // result variables for the wire
-    hidl_vec<uint8_t> resultKeyBlob;
-
-    // result variables the backend understands
-    keymaster_key_blob_t key_blob{nullptr, 0};
-
-    auto kmKeyBlobToUpgrade = hidlVec2KmKeyBlob(keyBlobToUpgrade);
-    auto kmUpgradeParams = hidlParams2KmParamSet(upgradeParams);
-
-    auto rc = keymaster_device_->upgrade_key(keymaster_device_, &kmKeyBlobToUpgrade,
-                                             &kmUpgradeParams, &key_blob);
-
-    if (rc == KM_ERROR_OK) {
-        // on success convert the result to wire format
-        resultKeyBlob = kmBlob2hidlVec(key_blob);
-    }
-
-    _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob);
-
-    if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material));
-
-    return Void();
-}
-
-Return<ErrorCode> KeymasterDevice::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
-    if (keymaster_device_->delete_key == nullptr) {
-        return ErrorCode::UNIMPLEMENTED;
-    }
-    auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob);
-    auto rc = legacy_enum_conversion(
-        keymaster_device_->delete_key(keymaster_device_, &kmKeyBlob));
-    // Keymaster 3.0 requires deleteKey to return ErrorCode::OK if the key
-    // blob is unusable after the call. This is equally true if the key blob was
-    // unusable before.
-    if (rc == ErrorCode::INVALID_KEY_BLOB) return ErrorCode::OK;
-    return rc;
-}
-
-Return<ErrorCode> KeymasterDevice::deleteAllKeys() {
-    if (keymaster_device_->delete_all_keys == nullptr) {
-        return ErrorCode::UNIMPLEMENTED;
-    }
-    return legacy_enum_conversion(keymaster_device_->delete_all_keys(keymaster_device_));
-}
-
-Return<ErrorCode> KeymasterDevice::destroyAttestationIds() {
-    return ErrorCode::UNIMPLEMENTED;
-}
-
-Return<void> KeymasterDevice::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
-                                    const hidl_vec<KeyParameter>& inParams, begin_cb _hidl_cb) {
-
-    // result variables for the wire
-    hidl_vec<KeyParameter> resultParams;
-    uint64_t resultOpHandle = 0;
-
-    // result variables the backend understands
-    keymaster_key_param_set_t out_params{nullptr, 0};
-    keymaster_operation_handle_t& operation_handle = resultOpHandle;
-
-    auto kmKey = hidlVec2KmKeyBlob(key);
-    auto kmInParams = hidlParams2KmParamSet(inParams);
-
-    auto rc = keymaster_device_->begin(keymaster_device_, legacy_enum_conversion(purpose), &kmKey,
-                                       &kmInParams, &out_params, &operation_handle);
-
-    if (rc == KM_ERROR_OK) resultParams = kmParamSet2Hidl(out_params);
-
-    _hidl_cb(legacy_enum_conversion(rc), resultParams, resultOpHandle);
-
-    keymaster_free_param_set(&out_params);
-
-    return Void();
-}
-
-Return<void> KeymasterDevice::update(uint64_t operationHandle,
-                                     const hidl_vec<KeyParameter>& inParams,
-                                     const hidl_vec<uint8_t>& input, update_cb _hidl_cb) {
-    // result variables for the wire
-    uint32_t resultConsumed = 0;
-    hidl_vec<KeyParameter> resultParams;
-    hidl_vec<uint8_t> resultBlob;
-
-    // result variables the backend understands
-    size_t consumed = 0;
-    keymaster_key_param_set_t out_params{nullptr, 0};
-    keymaster_blob_t out_blob{nullptr, 0};
-
-    auto kmInParams = hidlParams2KmParamSet(inParams);
-    auto kmInput = hidlVec2KmBlob(input);
-
-    auto rc = keymaster_device_->update(keymaster_device_, operationHandle, &kmInParams, &kmInput,
-                                        &consumed, &out_params, &out_blob);
-
-    if (rc == KM_ERROR_OK) {
-        resultConsumed = consumed;
-        resultParams = kmParamSet2Hidl(out_params);
-        resultBlob = kmBlob2hidlVec(out_blob);
-    }
-
-    _hidl_cb(legacy_enum_conversion(rc), resultConsumed, resultParams, resultBlob);
-
-    keymaster_free_param_set(&out_params);
-    if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data));
-
-    return Void();
-}
-
-Return<void> KeymasterDevice::finish(uint64_t operationHandle,
-                                     const hidl_vec<KeyParameter>& inParams,
-                                     const hidl_vec<uint8_t>& input,
-                                     const hidl_vec<uint8_t>& signature, finish_cb _hidl_cb) {
-    // result variables for the wire
-    hidl_vec<KeyParameter> resultParams;
-    hidl_vec<uint8_t> resultBlob;
-
-    // result variables the backend understands
-    keymaster_key_param_set_t out_params{nullptr, 0};
-    keymaster_blob_t out_blob{nullptr, 0};
-
-    auto kmInParams = hidlParams2KmParamSet(inParams);
-    auto kmInput = hidlVec2KmBlob(input);
-    auto kmSignature = hidlVec2KmBlob(signature);
-
-    auto rc = keymaster_device_->finish(keymaster_device_, operationHandle, &kmInParams, &kmInput,
-                                        &kmSignature, &out_params, &out_blob);
-
-    if (rc == KM_ERROR_OK) {
-        resultParams = kmParamSet2Hidl(out_params);
-        resultBlob = kmBlob2hidlVec(out_blob);
-    }
-
-    _hidl_cb(legacy_enum_conversion(rc), resultParams, resultBlob);
-
-    keymaster_free_param_set(&out_params);
-    if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data));
-
-    return Void();
-}
-
-Return<ErrorCode> KeymasterDevice::abort(uint64_t operationHandle) {
-    return legacy_enum_conversion(keymaster_device_->abort(keymaster_device_, operationHandle));
 }
 
 IKeymasterDevice* HIDL_FETCH_IKeymasterDevice(const char* name) {
-    keymaster2_device_t* dev = nullptr;
-
     ALOGI("Fetching keymaster device name %s", name);
 
-    uint32_t version = -1;
-    bool supports_ec = false;
-    bool supports_all_digests = false;
-
     if (name && strcmp(name, "softwareonly") == 0) {
-        dev = (new SoftKeymasterDevice(new SoftwareOnlyHidlKeymasterContext))->keymaster2_device();
+        return ::keymaster::ng::CreateKeymasterDevice();
     } else if (name && strcmp(name, "default") == 0) {
-        auto rc = keymaster_device_initialize(&dev, &version, &supports_ec, &supports_all_digests);
-        if (rc) return nullptr;
+        return createKeymaster3Device();
     }
-
-    auto kmrc = ::keymaster::ConfigureDevice(dev);
-    if (kmrc != KM_ERROR_OK) {
-        dev->common.close(&dev->common);
-        return nullptr;
-    }
-
-    return new KeymasterDevice(dev, version, supports_ec, supports_all_digests);
+    return nullptr;
 }
 
 }  // namespace implementation
diff --git a/keymaster/3.0/default/KeymasterDevice.h b/keymaster/3.0/default/KeymasterDevice.h
index e048d5b..267bf85 100644
--- a/keymaster/3.0/default/KeymasterDevice.h
+++ b/keymaster/3.0/default/KeymasterDevice.h
@@ -18,78 +18,14 @@
 #ifndef HIDL_GENERATED_android_hardware_keymaster_V3_0_KeymasterDevice_H_
 #define HIDL_GENERATED_android_hardware_keymaster_V3_0_KeymasterDevice_H_
 
-#include <hardware/keymaster2.h>
-
 #include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
-#include <hidl/Status.h>
 
-#include <hidl/MQDescriptor.h>
 namespace android {
 namespace hardware {
 namespace keymaster {
 namespace V3_0 {
 namespace implementation {
 
-using ::android::hardware::keymaster::V3_0::ErrorCode;
-using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
-using ::android::hardware::keymaster::V3_0::KeyCharacteristics;
-using ::android::hardware::keymaster::V3_0::KeyFormat;
-using ::android::hardware::keymaster::V3_0::KeyParameter;
-using ::android::hardware::keymaster::V3_0::KeyPurpose;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
-using ::android::sp;
-
-class KeymasterDevice : public IKeymasterDevice {
-  public:
-    KeymasterDevice(keymaster2_device_t* dev, uint32_t hardware_version, bool hardware_supports_ec,
-                    bool hardware_supports_all_digests)
-        : keymaster_device_(dev), hardware_version_(hardware_version),
-          hardware_supports_ec_(hardware_supports_ec),
-          hardware_supports_all_digests_(hardware_supports_all_digests) {}
-    virtual ~KeymasterDevice();
-
-    // Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow.
-    Return<void> getHardwareFeatures(getHardwareFeatures_cb _hidl_cb);
-    Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
-    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
-                             generateKey_cb _hidl_cb) override;
-    Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
-                                       const hidl_vec<uint8_t>& clientId,
-                                       const hidl_vec<uint8_t>& appData,
-                                       getKeyCharacteristics_cb _hidl_cb) override;
-    Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
-                           const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
-    Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
-                           const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
-                           exportKey_cb _hidl_cb) override;
-    Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
-                           const hidl_vec<KeyParameter>& attestParams,
-                           attestKey_cb _hidl_cb) override;
-    Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
-                            const hidl_vec<KeyParameter>& upgradeParams,
-                            upgradeKey_cb _hidl_cb) override;
-    Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
-    Return<ErrorCode> deleteAllKeys() override;
-    Return<ErrorCode> destroyAttestationIds() override;
-    Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
-                       const hidl_vec<KeyParameter>& inParams, begin_cb _hidl_cb) override;
-    Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
-                        const hidl_vec<uint8_t>& input, update_cb _hidl_cb) override;
-    Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
-                        const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
-                        finish_cb _hidl_cb) override;
-    Return<ErrorCode> abort(uint64_t operationHandle) override;
-
-  private:
-    keymaster2_device_t* keymaster_device_;
-    uint32_t hardware_version_;
-    bool hardware_supports_ec_;
-    bool hardware_supports_all_digests_;
-};
-
 extern "C" IKeymasterDevice* HIDL_FETCH_IKeymasterDevice(const char* name);
 
 }  // namespace implementation
diff --git a/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc b/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
index 849d270..086ba2f 100644
--- a/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
+++ b/keymaster/3.0/default/android.hardware.keymaster@3.0-service.rc
@@ -1,4 +1,4 @@
-service keymaster-3-0 /vendor/bin/hw/android.hardware.keymaster@3.0-service
+service vendor.keymaster-3-0 /vendor/bin/hw/android.hardware.keymaster@3.0-service
     class early_hal
     user system
     group system drmrpc
diff --git a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
index e7b222a..6abd9bf 100644
--- a/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/3.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -898,13 +898,20 @@
         }
     }
 
-    void CheckOrigin() {
+    void CheckOrigin(bool asymmetric = false) {
         SCOPED_TRACE("CheckOrigin");
         if (is_secure_ && supports_symmetric_) {
             EXPECT_TRUE(
                 contains(key_characteristics_.teeEnforced, TAG_ORIGIN, KeyOrigin::IMPORTED));
         } else if (is_secure_) {
-            EXPECT_TRUE(contains(key_characteristics_.teeEnforced, TAG_ORIGIN, KeyOrigin::UNKNOWN));
+            // wrapped KM0
+            if (asymmetric) {
+                EXPECT_TRUE(
+                    contains(key_characteristics_.teeEnforced, TAG_ORIGIN, KeyOrigin::UNKNOWN));
+            } else {
+                EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, TAG_ORIGIN,
+                                     KeyOrigin::IMPORTED));
+            }
         } else {
             EXPECT_TRUE(
                 contains(key_characteristics_.softwareEnforced, TAG_ORIGIN, KeyOrigin::IMPORTED));
@@ -993,8 +1000,8 @@
                                    HidlBuf(app_id));
 
     if (!KeymasterHidlTest::IsSecure()) {
-        // SW is KM2
-        EXPECT_EQ(att_keymaster_version, 2U);
+        // SW is KM3
+        EXPECT_EQ(att_keymaster_version, 3U);
     }
 
     if (KeymasterHidlTest::SupportsSymmetric()) {
@@ -1059,13 +1066,17 @@
 
 class NewKeyGenerationTest : public KeymasterHidlTest {
   protected:
-    void CheckBaseParams(const KeyCharacteristics& keyCharacteristics) {
+    void CheckBaseParams(const KeyCharacteristics& keyCharacteristics, bool asymmetric = false) {
         // TODO(swillden): Distinguish which params should be in which auth list.
 
         AuthorizationSet auths(keyCharacteristics.teeEnforced);
         auths.push_back(AuthorizationSet(keyCharacteristics.softwareEnforced));
 
-        EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+        if (!SupportsSymmetric() && asymmetric) {
+            EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::UNKNOWN));
+        } else {
+            EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+        }
 
         EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
         EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::VERIFY));
@@ -1114,7 +1125,7 @@
                                              &key_blob, &key_characteristics));
 
         ASSERT_GT(key_blob.size(), 0U);
-        CheckBaseParams(key_characteristics);
+        CheckBaseParams(key_characteristics, true /* asymmetric */);
 
         AuthorizationSet crypto_params;
         if (IsSecure()) {
@@ -1160,7 +1171,7 @@
                                                  .Authorizations(UserAuths()),
                                              &key_blob, &key_characteristics));
         ASSERT_GT(key_blob.size(), 0U);
-        CheckBaseParams(key_characteristics);
+        CheckBaseParams(key_characteristics, true /* asymmetric */);
 
         AuthorizationSet crypto_params;
         if (IsSecure()) {
@@ -1565,7 +1576,9 @@
                                           .Digest(Digest::NONE)
                                           .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
     string result;
-    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+    ErrorCode finish_error_code = Finish(message, &result);
+    EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH ||
+                finish_error_code == ErrorCode::INVALID_ARGUMENT);
 
     // Very large message that should exceed the transfer buffer size of any reasonable TEE.
     message = string(128 * 1024, 'a');
@@ -1573,7 +1586,9 @@
               Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
                                           .Digest(Digest::NONE)
                                           .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
-    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+    finish_error_code = Finish(message, &result);
+    EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH ||
+                finish_error_code == ErrorCode::INVALID_ARGUMENT);
 }
 
 /*
@@ -2279,8 +2294,7 @@
  * Verifies that attempting to export RSA keys from corrupted key blobs fails.  This is essentially
  * a poor-man's key blob fuzzer.
  */
-// Disabled due to b/33385206
-TEST_F(ExportKeyTest, DISABLED_RsaCorruptedKeyBlob) {
+TEST_F(ExportKeyTest, RsaCorruptedKeyBlob) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .RsaSigningKey(1024, 3)
@@ -2303,8 +2317,7 @@
  * Verifies that attempting to export ECDSA keys from corrupted key blobs fails.  This is
  * essentially a poor-man's key blob fuzzer.
  */
-// Disabled due to b/33385206
-TEST_F(ExportKeyTest, DISABLED_EcCorruptedKeyBlob) {
+TEST_F(ExportKeyTest, EcCorruptedKeyBlob) {
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                              .Authorization(TAG_NO_AUTH_REQUIRED)
                                              .EcdsaSigningKey(EcCurve::P_256)
@@ -2357,7 +2370,7 @@
     CheckKm0CryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
     CheckKm1CryptoParam(TAG_DIGEST, Digest::SHA_2_256);
     CheckKm1CryptoParam(TAG_PADDING, PaddingMode::RSA_PSS);
-    CheckOrigin();
+    CheckOrigin(true /* asymmetric */);
 
     string message(1024 / 8, 'a');
     auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS);
@@ -2413,7 +2426,7 @@
     CheckKm1CryptoParam(TAG_DIGEST, Digest::SHA_2_256);
     CheckKm2CryptoParam(TAG_EC_CURVE, EcCurve::P_256);
 
-    CheckOrigin();
+    CheckOrigin(true /* asymmetric */);
 
     string message(32, 'a');
     auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
@@ -2439,7 +2452,7 @@
     CheckKm1CryptoParam(TAG_DIGEST, Digest::SHA_2_256);
     CheckKm2CryptoParam(TAG_EC_CURVE, EcCurve::P_521);
 
-    CheckOrigin();
+    CheckOrigin(true /* asymmetric */);
 
     string message(32, 'a');
     auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
diff --git a/keymaster/4.0/Android.bp b/keymaster/4.0/Android.bp
new file mode 100644
index 0000000..2daad41
--- /dev/null
+++ b/keymaster/4.0/Android.bp
@@ -0,0 +1,42 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.keymaster@4.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IKeymasterDevice.hal",
+    ],
+    interfaces: [
+        "android.hardware.keymaster@3.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "Algorithm",
+        "BlockMode",
+        "Constants",
+        "Digest",
+        "EcCurve",
+        "ErrorCode",
+        "HardwareAuthToken",
+        "HardwareAuthenticatorType",
+        "HmacSharingParameters",
+        "KeyBlobUsageRequirements",
+        "KeyCharacteristics",
+        "KeyDerivationFunction",
+        "KeyFormat",
+        "KeyOrigin",
+        "KeyParameter",
+        "KeyPurpose",
+        "PaddingMode",
+        "SecurityLevel",
+        "Tag",
+        "TagType",
+        "VerificationToken",
+    ],
+    gen_java: false,
+}
+
diff --git a/keymaster/4.0/IKeymasterDevice.hal b/keymaster/4.0/IKeymasterDevice.hal
new file mode 100644
index 0000000..aef81c7
--- /dev/null
+++ b/keymaster/4.0/IKeymasterDevice.hal
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.keymaster@4.0;
+
+import android.hardware.keymaster@3.0::ErrorCode;
+import android.hardware.keymaster@3.0::KeyFormat;
+
+/**
+ * Keymaster device definition.  For thorough documentation see the implementer's reference, at
+ * https://source.android.com/security/keystore/implementer-ref.html
+ */
+interface IKeymasterDevice {
+
+    /**
+     * Returns information about the underlying Keymaster hardware.
+     *
+     * @return security level of the Keymaster implementation accessed through this HAL.
+     *
+     * @return keymasterName is the name of the Keymaster implementation.
+     *
+     * @return keymasterAuthorName is the name of the author of the Keymaster implementation
+     *         (organization name, not individual).
+     */
+    getHardwareInfo()
+        generates (SecurityLevel securityLevel, string keymasterName, string keymasterAuthorName);
+
+    /**
+     * Start the creation of an HMAC key, shared with another Keymaster implementation.  Any device
+     * with a StrongBox Keymaster has two Keymaster instances, because there must be a TEE Keymaster
+     * as well.  The HMAC key used to MAC and verify authentication tokens must be shared between
+     * TEE and StrongBox so they can each validate tokens produced by the other.  This method is the
+     * first step in the process for for agreeing on a shared key.  It is called by Keystore during
+     * startup if and only if Keystore loads multiple Keymaster HALs.  Keystore calls it on each of
+     * the HAL instances and collects the results in preparation for the second step.
+     */
+    getHmacSharingParameters() generates (ErrorCode error, HmacSharingParameters params);
+
+    /**
+     * Complete the creation of an HMAC key, shared with another Keymaster implementation.  Any
+     * device with a StrongBox Keymaster has two Keymasters instances, because there must be a TEE
+     * Keymaster as well.  The HMAC key used to MAC and verify authentication tokens must be shared
+     * between TEE and StrongBox so they can each validate tokens produced by the other.  This
+     * method is the second and final step in the process for agreeing on a shared key.  It is
+     * called by Keystore during startup if and only if Keystore loads multiple Keymaster HALs.
+     * Keystore calls it on each of the HAL instances, and sends to it all of the
+     * HmacSharingParameters returned by all HALs.
+     *
+     * This method computes the shared 32-byte HMAC ``H'' as follows (all Keymaster instances
+     * perform the same computation to arrive at the same result):
+     *
+     *     H = CKDF(key = K,
+     *              context = P1 || P2 || ... || Pn,
+     *              label = "KeymasterSharedMac")
+     *
+     * where:
+     *
+     *     ``CKDF'' is the standard AES-CMAC KDF from NIST SP 800-108 in counter mode (see Section
+     *           5.1 of the referenced publication).  ``key'', ``context'', and ``label'' are
+     *           defined in the standard.  The counter is prefixed, as shown in the construction on
+     *           page 12 of the standard.  The label string is UTF-8 encoded.
+     *
+     *     ``K'' is a pre-established shared secret, set up during factory reset.  The mechanism for
+     *           establishing this shared secret is implementation-defined, but see below for a
+     *           recommended approach, which assumes that the TEE Keymaster does not have storage
+     *           available to it, but the StrongBox Keymaster does.
+     *
+     *           <b>CRITICAL SECURITY REQUIREMENT</b>: All keys created by a Keymaster instance must
+     *           be cryptographically bound to the value of K, such that establishing a new K
+     *           permanently destroys them.
+     *
+     *     ``||'' represents concatenation.
+     *
+     *     ``Pi'' is the i'th HmacSharingParameters value in the params vector.  Note that at
+     *           present only two Keymaster implementations are supported, but this mechanism
+     *           extends without modification to any number of implementations.  Encoding of an
+     *           HmacSharingParameters is the concatenation of its two fields, i.e. seed || nonce.
+     *
+     * Process for establishing K:
+     *
+     *     Any method of securely establishing K that ensures that an attacker cannot obtain or
+     *     derive its value is acceptable.  What follows is a recommended approach, to be executed
+     *     during each factory reset.  It relies on use of the factory-installed attestation keys to
+     *     mitigate man-in-the-middle attacks.  This protocol requires that one of the instances
+     *     have secure persistent storage.  This model was chosen because StrongBox has secure
+     *     persistent storage (by definition), but the TEE may not.  The instance without storage is
+     *     assumed to be able to derive a unique hardware-bound key (HBK) which is used only for
+     *     this purpose, and is not derivable outside of the secure environment..
+     *
+     *     In what follows, T is the Keymaster instance without storage, S is the Keymaster instance
+     *     with storage:
+     *
+     *     1. T generates an ephemeral EC P-256 key pair K1
+     *     2. T sends K1_pub to S, signed with T's attestation key.
+     *     3. S validates the signature on K1_pub.
+     *     4. S generates an ephemeral EC P-256 key pair K2.
+     *     5. S sends {K1_pub, K2_pub}, to T, signed with S's attestation key.
+     *     6. T validates the signature on {K1_pub, K2_pub}
+     *     7. T uses {K1_priv, K2_pub} with ECDH to compute session secret Q.
+     *     8. T generates a random seed S
+     *     9. T computes K = KDF(HBK, S), where KDF is some secure key derivation function.
+     *     10. T sends M = AES-GCM-ENCRYPT(Q, {S || K}) to S.
+     *     10. S uses {K2_priv, K1_pub} with ECDH to compute session secret Q.
+     *     11. S computes S || K = AES-GCM-DECRYPT(Q, M) and stores S and K.
+     *
+     *     When S receives the getHmacSharingParameters call, it returns the stored S as the seed
+     *     and a nonce.  When T receives the same call, it returns an empty seed and a nonce.  When
+     *     T receives the computeSharedHmac call, it uses the seed provided by S to compute K.  S,
+     *     of course, has K stored.
+     *
+     * @param params The HmacSharingParameters data returned by all Keymaster instances when
+     *        getHmacSharingParameters was called.
+     *
+     * @return sharingCheck A 32-byte value used to verify that all Keymaster instances have
+     *         computed the same shared HMAC key.  The sharingCheck value is computed as follows:
+     *
+     *             sharingCheck = HMAC(H, "Keymaster HMAC Verification")
+     *
+     *         The string is UTF-8 encoded.  If the returned values of all Keymaster instances don't
+     *         match, Keystore will assume that HMAC agreement failed.
+     */
+    computeSharedHmac(vec<HmacSharingParameters> params)
+        generates (ErrorCode error, vec<uint8_t> sharingCheck);
+
+    /**
+     * Verify authorizations for another Keymaster instance.
+     *
+     * On systems with both a StrongBox and a TEE Keymaster instance it is sometimes useful to ask
+     * the TEE Keymaster to verify authorizations for a key hosted in StrongBox.
+     *
+     * For every StrongBox operation, Keystore is required to call this method on the TEE Keymaster,
+     * passing in the StrongBox key's hardwareEnforced authorization list and the operation handle
+     * returned by StrongBox begin().  The TEE Keymaster must validate all of the authorizations it
+     * can and return those it validated in the VerificationToken.  If it cannot verify any, the
+     * parametersVerified field of the VerificationToken must be empty.  Keystore must then pass the
+     * VerificationToken to the subsequent invocations of StrongBox update() and finish().
+     *
+     * StrongBox implementations must return ErrorCode::UNIMPLEMENTED.
+     *
+     * @param operationHandle the operation handle returned by StrongBox Keymaster's begin().
+     *
+     * @param parametersToVerify Set of authorizations to verify.
+     *
+     * @param authToken A HardwareAuthToken if needed to authorize key usage.
+     */
+    verifyAuthorization(uint64_t operationHandle, vec<KeyParameter> parametersToVerify,
+                        HardwareAuthToken authToken)
+        generates (ErrorCode error, VerificationToken token);
+
+
+    /**
+     * Adds entropy to the RNG used by Keymaster.  Entropy added through this method is guaranteed
+     * not to be the only source of entropy used, and the mixing function is required to be secure,
+     * in the sense that if the RNG is seeded (from any source) with any data the attacker cannot
+     * predict (or control), then the RNG output is indistinguishable from random.  Thus, if the
+     * entropy from any source is good, the output must be good.
+     *
+     * @param data Bytes to be mixed into the RNG.
+     *
+     * @return error See the ErrorCode enum in types.hal.
+     */
+    addRngEntropy(vec<uint8_t> data) generates (ErrorCode error);
+
+    /**
+     * Generates a key, or key pair, returning a key blob and a description of the key.
+     *
+     * @param keyParams Key generation parameters are defined as Keymaster tag/value pairs, provided
+     *        in params.  See Tag in types.hal for the full list.
+     *
+     * @return error See the ErrorCode enum in types.hal.
+     *
+     * @return keyBlob Opaque, encrypted descriptor of the generated key.  A recommended
+     *        implementation strategy is to include an encrypted copy of the key material, wrapped
+     *        in a key unavailable outside secure hardware.
+     *
+     * @return keyCharacteristics Description of the generated key.  See KeyCharacteristis in
+     *         types.hal.
+     */
+    generateKey(vec<KeyParameter> keyParams)
+        generates (ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
+
+    /**
+     * Imports a key, or key pair, returning a key blob and/or a description of the key.
+     *
+     * @param keyParams Key generation parameters are defined as Keymaster tag/value pairs, provided
+     *        in params.  See Tag for the full list.
+     *
+     * @param keyFormat The format of the key material to import.
+     *
+     * @pram keyData The key material to import, in the format specifed in keyFormat.
+     *
+     * @return error See the ErrorCode enum.
+     *
+     * @return keyBlob Opaque, encrypted descriptor of the generated key, which will generally
+     *         contain a copy of the key material, wrapped in a key unavailable outside secure
+     *         hardware.
+     *
+     * @return keyCharacteristics Decription of the generated key.
+     */
+    importKey(vec<KeyParameter> keyParams, KeyFormat keyFormat, vec<uint8_t> keyData)
+        generates (ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
+
+    /**
+     * Securely imports a key, or key pair, returning a key blob and a description of the imported
+     * key.
+     *
+     * @param wrappedKeyData The wrapped key material to import.  The wrapped key is in DER-encoded
+     * ASN.1 format, specified by the following schema:
+     *
+     *     KeyDescription ::= SEQUENCE(
+     *         keyFormat INTEGER,                   # Values from KeyFormat enum.
+     *         keyParams AuthorizationList,
+     *     )
+     *
+     *     SecureKeyWrapper ::= SEQUENCE(
+     *         version INTEGER,                     # Contains value 0
+     *         encryptedTransportKey OCTET_STRING,
+     *         initializationVector OCTET_STRING,
+     *         keyDescription KeyDescription,
+     *         encryptedKey OCTET_STRING,
+     *         tag OCTET_STRING
+     *     )
+     *
+     *     Where:
+     *
+     *     o keyFormat is an integer from the KeyFormat enum, defining the format of the plaintext
+     *       key material.
+     *     o keyParams is the characteristics of the key to be imported (as with generateKey or
+     *       importKey).  If the secure import is successful, these characteristics must be
+     *       associated with the key exactly as if the key material had been insecurely imported
+     *       with the @3.0::IKeymasterDevice::importKey.
+     *     o encryptedTransportKey is a 256-bit AES key, XORed with a masking key and then encrypted
+     *       in RSA-OAEP mode (SHA-256 digest, SHA-1 MGF1 digest) with the wrapping key specified by
+     *       wrappingKeyBlob.
+     *     o keyDescription is a KeyDescription, above.
+     *     o encryptedKey is the key material of the key to be imported, in format keyFormat, and
+     *       encrypted with encryptedEphemeralKey in AES-GCM mode, with the DER-encoded
+     *       representation of keyDescription provided as additional authenticated data.
+     *     o tag is the tag produced by the AES-GCM encryption of encryptedKey.
+     *
+     * So, importWrappedKey does the following:
+     *
+     *     1. Get the private key material for wrappingKeyBlob, verifying that the wrapping key has
+     *        purpose KEY_WRAP, padding mode RSA_OAEP, and digest SHA_2_256, returning the
+     *        appropriate error if any of those requirements fail.
+     *     2. Extract the encryptedTransportKey field from the SecureKeyWrapper, and decrypt
+     *        it with the wrapping key.
+     *     3. XOR the result of step 2 with maskingKey.
+     *     4. Use the result of step 3 as an AES-GCM key to decrypt encryptedKey, using the encoded
+     *        value of keyDescription as the additional authenticated data.  Call the result
+     *        "keyData" for the next step.
+     *     5. Perform the equivalent of calling importKey(keyParams, keyFormat, keyData), except
+     *        that the origin tag should be set to SECURELY_IMPORTED.
+     *
+     * @param wrappingKeyBlob The opaque key descriptor returned by generateKey() or importKey().
+     *        This key must have been created with Purpose::WRAP_KEY, and must be a key algorithm
+     *        that supports encryption and must be at least as strong (in key size) as the key to be
+     *        imported (per NIST key length recommendations: 112 bits symmetric is equivalent to
+     *        2048-bit RSA or 224-bit EC, 128 bits symmetric ~ 3072-bit RSA or 256-bit EC, etc.).
+     *
+     * @param maskingKey The 32-byte value XOR'd with the transport key in the SecureWrappedKey
+     *        structure.
+     *
+     * @param unwrappingParams must contain any parameters needed to perform the unwrapping
+     *        operation.  For example, if the wrapping key is an AES key the block and padding modes
+     *        must be specified in this argument.
+     *
+     * @param passwordSid specifies the password secure ID (SID) of the user that owns the key being
+     *        installed.  If the authorization list in wrappedKeyData contains a Tag::USER_SECURE_ID
+     *        with a value that has the HardwareAuthenticatorType::PASSWORD bit set, the constructed
+     *        key must be bound to the SID value provided by this argument.  If the wrappedKeyData
+     *        does not contain such a tag and value, this argument must be ignored.
+     *
+     * @param biometricSid specifies the biometric secure ID (SID) of the user that owns the key
+     *        being installed.  If the authorization list in wrappedKeyData contains a
+     *        Tag::USER_SECURE_ID with a value that has the HardwareAuthenticatorType::FINGERPRINT
+     *        bit set, the constructed key must be bound to the SID value provided by this argument.
+     *        If the wrappedKeyData does not contain such a tag and value, this argument must be
+     *        ignored.
+     *
+     * @return error See the ErrorCode enum.
+     *
+     * @return keyBlob Opaque descriptor of the imported key.  It is recommended that the keyBlob
+     *         contain a copy of the key material, wrapped in a key unavailable outside secure
+     *         hardware.
+     */
+    importWrappedKey(vec<uint8_t> wrappedKeyData, vec<uint8_t> wrappingKeyBlob,
+                     vec<uint8_t> maskingKey, vec<KeyParameter> unwrappingParams,
+                     uint64_t passwordSid, uint64_t biometricSid)
+        generates(ErrorCode error, vec<uint8_t> keyBlob, KeyCharacteristics keyCharacteristics);
+
+    /**
+     * Returns the characteristics of the specified key, if the keyBlob is valid (implementations
+     * must fully validate the integrity of the key).
+     *
+     * @param keyBlob The opaque descriptor returned by generateKey() or importKey();
+     *
+     * @param clientId An opaque byte string identifying the client.  This value must match the
+     *        Tag::APPLICATION_ID data provided during key generation/import.  Without the correct
+     *        value, it must be computationally infeasible for the secure hardware to obtain the key
+     *        material.
+     *
+     * @param appData An opaque byte string provided by the application.  This value must match the
+     *        Tag::APPLICATION_DATA data provided during key generation/import.  Without the correct
+     *        value, it must be computationally infeasible for the secure hardware to obtain the key
+     *        material.
+     *
+     * @return error See the ErrorCode enum in types.hal.
+     *
+     * @return keyCharacteristics Decription of the generated key.  See KeyCharacteristis in
+     *         types.hal.
+     */
+    getKeyCharacteristics(vec<uint8_t> keyBlob, vec<uint8_t> clientId, vec<uint8_t> appData)
+        generates (ErrorCode error, KeyCharacteristics keyCharacteristics);
+
+    /**
+     * Exports a public key, returning the key in the specified format.
+     *
+     * @parm keyFormat The format used for export.  See KeyFormat in types.hal.
+     *
+     * @param keyBlob The opaque descriptor returned by generateKey() or importKey().  The
+     *        referenced key must be asymmetric.
+     *
+     * @param clientId An opaque byte string identifying the client.  This value must match the
+     *        Tag::APPLICATION_ID data provided during key generation/import.  Without the correct
+     *        value, it must be computationally infeasible for the secure hardware to obtain the key
+     *        material.
+     *
+     * @param appData An opaque byte string provided by the application.  This value must match the
+     *        Tag::APPLICATION_DATA data provided during key generation/import.  Without the correct
+     *        value, it must be computationally infeasible for the secure hardware to obtain the key
+     *        material.
+     *
+     * @return error See the ErrorCode enum in types.hal.
+     *
+     * @return keyMaterial The public key material in PKCS#8 format.
+     */
+    exportKey(KeyFormat keyFormat, vec<uint8_t> keyBlob, vec<uint8_t> clientId,
+              vec<uint8_t> appData) generates (ErrorCode error, vec<uint8_t> keyMaterial);
+
+    /**
+     * Generates a signed X.509 certificate chain attesting to the presence of keyToAttest in
+     * Keymaster.  The certificate must contain an extension with OID 1.3.6.1.4.1.11129.2.1.17 and
+     * value defined in:
+     *
+     *     https://developer.android.com/training/articles/security-key-attestation.html.
+     *
+     * @param keyToAttest The opaque descriptor returned by generateKey() or importKey().  The
+     *        referenced key must be asymmetric.
+     *
+     * @param attestParams Parameters for the attestation, notably Tag::ATTESTATION_CHALLENGE.
+     *
+     * @return error See the ErrorCode enum in types.hal.
+     *
+     * @return certChain The attestation certificate, and additional certificates back to the root
+     *         attestation certificate, which clients will need to check against a known-good value.
+     */
+    attestKey(vec<uint8_t> keyToAttest, vec<KeyParameter> attestParams)
+        generates (ErrorCode error, vec<vec<uint8_t>> certChain);
+
+    /**
+     * Upgrades an old key blob.  Keys can become "old" in two ways: Keymaster can be upgraded to a
+     * new version with an incompatible key blob format, or the system can be updated to invalidate
+     * the OS version (OS_VERSION tag), system patch level (OS_PATCHLEVEL tag), vendor patch level
+     * (VENDOR_PATCH_LEVEL tag), boot patch level (BOOT_PATCH_LEVEL tag) or other,
+     * implementation-defined patch level (keymaster implementers are encouraged to extend this HAL
+     * with a minor version extension to define validatable patch levels for other images; tags
+     * must be defined in the implemeter's namespace, starting at 10000).  In either case,
+     * attempts to use an old key blob with getKeyCharacteristics(), exportKey(), attestKey() or
+     * begin() must result in Keymaster returning ErrorCode::KEY_REQUIRES_UPGRADE.  The caller must
+     * use this method to upgrade the key blob.
+     *
+     * If upgradeKey is asked to update a key with any version or patch level that is higher than
+     * the current system version or patch level, it must return ErrorCode::INVALID_ARGUMENT.  There
+     * is one exception: it is always permissible to "upgrade" from any OS_VERSION number to
+     * OS_VERSION 0.  For example, if the key has OS_VERSION 080001, it is permisible to upgrade the
+     * key if the current system version is 080100, because the new version is larger, or if the
+     * current system version is 0, because upgrades to 0 are always allowed.  If the system version
+     * were 080000, however, keymaster must return ErrorCode::INVALID_ARGUMENT because that value is
+     * smaller than 080001.
+     *
+     * Note that Keymaster versions 2 and 3 required that the system and boot images have the same
+     * patch level and OS version.  This requirement is relaxed for Keymaster 4, and the OS version
+     * in the boot image footer is no longer used.
+     *
+     * @param keyBlobToUpgrade The opaque descriptor returned by generateKey() or importKey();
+     *
+     * @param upgradeParams A parameter list containing any parameters needed to complete the
+     *        upgrade, including Tag::APPLICATION_ID and Tag::APPLICATION_DATA.
+     *
+     * @return error See the ErrorCode enum.
+     *
+     * @return upgradedKeyBlob A new key blob that references the same key as keyBlobToUpgrade, but
+     *         is in the new format, or has the new version data.
+     */
+    upgradeKey(vec<uint8_t> keyBlobToUpgrade, vec<KeyParameter> upgradeParams)
+        generates (ErrorCode error, vec<uint8_t> upgradedKeyBlob);
+
+    /**
+     * Deletes the key, or key pair, associated with the key blob.  Calling this function on a key
+     * with Tag::ROLLBACK_RESISTANCE in its hardware-enforced authorization list must render the key
+     * permanently unusable.  Keys without Tag::ROLLBACK_RESISTANCE may or may not be rendered
+     * unusable.
+     *
+     * @param keyBlob The opaque descriptor returned by generateKey() or importKey();
+     *
+     * @return error See the ErrorCode enum.
+     */
+    deleteKey(vec<uint8_t> keyBlob) generates (ErrorCode error);
+
+    /**
+     * Deletes all keys in the hardware keystore.  Used when keystore is reset completely.  After
+     * this function is called all keys with Tag::ROLLBACK_RESISTANCE in their hardware-enforced
+     * authorization lists must be rendered permanently unusable.  Keys without
+     * Tag::ROLLBACK_RESISTANCE may or may not be rendered unusable.
+     *
+     * @return error See the ErrorCode enum.
+     */
+    deleteAllKeys() generates (ErrorCode error);
+
+    /**
+     * Destroys knowledge of the device's ids.  This prevents all device id attestation in the
+     * future.  The destruction must be permanent so that not even a factory reset will restore the
+     * device ids.
+     *
+     * Device id attestation may be provided only if this method is fully implemented, allowing the
+     * user to permanently disable device id attestation.  If this cannot be guaranteed, the device
+     * must never attest any device ids.
+     *
+     * This is a NOP if device id attestation is not supported.
+     *
+     * @return error See the ErrorCode enum.
+     */
+    destroyAttestationIds() generates (ErrorCode error);
+
+    /**
+     * Begins a cryptographic operation using the specified key.  If all is well, begin() must
+     * return ErrorCode::OK and create an operation handle which must be passed to subsequent calls
+     * to update(), finish() or abort().
+     *
+     * It is critical that each call to begin() be paired with a subsequent call to finish() or
+     * abort(), to allow the Keymaster implementation to clean up any internal operation state.  The
+     * caller's failure to do this may leak internal state space or other internal resources and may
+     * eventually cause begin() to return ErrorCode::TOO_MANY_OPERATIONS when it runs out of space
+     * for operations.  Any result other than ErrorCode::OK from begin(), update() or finish()
+     * implicitly aborts the operation, in which case abort() need not be called (and must return
+     * ErrorCode::INVALID_OPERATION_HANDLE if called).
+     *
+     * @param purpose The purpose of the operation, one of KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT,
+     *        KeyPurpose::SIGN or KeyPurpose::VERIFY.  Note that for AEAD modes, encryption and
+     *        decryption imply signing and verification, respectively, but must be specified as
+     *        KeyPurpose::ENCRYPT and KeyPurpose::DECRYPT.
+     *
+     * @param keyBlob The opaque key descriptor returned by generateKey() or importKey().  The key
+     *        must have a purpose compatible with purpose and all of its usage requirements must be
+     *        satisfied, or begin() must return an appropriate error code.
+     *
+     * @param inParams Additional parameters for the operation.  If Tag::APPLICATION_ID or
+     *        Tag::APPLICATION_DATA were provided during generation, they must be provided here, or
+     *        the operation must fail with ErrorCode::INVALID_KEY_BLOB.  For operations that require
+     *        a nonce or IV, on keys that were generated with Tag::CALLER_NONCE, inParams may
+     *        contain a tag Tag::NONCE.  If Tag::NONCE is provided for a key without
+     *        Tag:CALLER_NONCE, ErrorCode::CALLER_NONCE_PROHIBITED must be returned.
+     *
+     * @param authToken Authentication token.  Callers that provide no token must set all numeric
+     *        fields to zero and the MAC must be an empty vector.
+     *
+     * @return error See the ErrorCode enum in types.hal.
+     *
+     * @return outParams Output parameters.  Used to return additional data from the operation
+     *         initialization, notably to return the IV or nonce from operations that generate an IV
+     *         or nonce.
+     *
+     * @return operationHandle The newly-created operation handle which must be passed to update(),
+     *         finish() or abort().
+     */
+    begin(KeyPurpose purpose, vec<uint8_t> keyBlob, vec<KeyParameter> inParams,
+          HardwareAuthToken authToken)
+        generates (ErrorCode error, vec<KeyParameter> outParams, OperationHandle operationHandle);
+
+    /**
+     * Provides data to, and possibly receives output from, an ongoing cryptographic operation begun
+     * with begin().
+     *
+     * If operationHandle is invalid, update() must return ErrorCode::INVALID_OPERATION_HANDLE.
+     *
+     * update() may not consume all of the data provided in the data buffer.  update() must return
+     * the amount consumed in inputConsumed.  The caller may provide the unconsumed data in a
+     * subsequent call.
+     *
+     * @param operationHandle The operation handle returned by begin().
+     *
+     * @param inParams Additional parameters for the operation.  For AEAD modes, this is used to
+     *        specify Tag::ADDITIONAL_DATA.  Note that additional data may be provided in multiple
+     *        calls to update(), but only until input data has been provided.
+     *
+     * @param input Data to be processed.  Note that update() may or may not consume all of the data
+     *        provided.  See inputConsumed.
+     *
+     * @param authToken Authentication token.  Callers that provide no token must set all numeric
+     *        fields to zero and the MAC must be an empty vector.
+     *
+     * @param verificationToken Verification token, used to prove that another Keymaster HAL has
+     *        verified some parameters, and to deliver the other HAL's current timestamp, if needed.
+     *        If not provided, all fields must be initialized to zero and vectors empty.
+     *
+     * @return error See the ErrorCode enum in types.hal.
+     *
+     * @return inputConsumed Amount of data that was consumed by update().  If this is less than the
+     *         amount provided, the caller may provide the remainder in a subsequent call to
+     *         update() or finish().  Every call to update must consume at least one byte, and
+     *         implementations should consume as much data as reasonably possible for each call.
+     *
+     * @return outParams Output parameters, used to return additional data from the operation.
+     *
+     * @return output The output data, if any.
+     */
+    update(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input,
+           HardwareAuthToken authToken, VerificationToken verificationToken)
+        generates (ErrorCode error, uint32_t inputConsumed, vec<KeyParameter> outParams,
+                   vec<uint8_t> output);
+
+    /**
+     * Finalizes a cryptographic operation begun with begin() and invalidates operationHandle.
+     *
+     * @param operationHandle The operation handle returned by begin().  This handle must be invalid
+     *        when finish() returns.
+     *
+     * @param inParams Additional parameters for the operation.  For AEAD modes, this is used to
+     *        specify Tag::ADDITIONAL_DATA, but only if no input data was provided to update().
+     *
+     * @param input Data to be processed, per the parameters established in the call to begin().
+     *        finish() must consume all provided data or return ErrorCode::INVALID_INPUT_LENGTH.
+     *
+     * @param signature The signature to be verified if the purpose specified in the begin() call
+     *        was KeyPurpose::VERIFY.
+     *
+     * @param authToken Authentication token.  Callers that provide no token must set all numeric
+     *        fields to zero and the MAC must be an empty vector.
+     *
+     * @param verificationToken Verification token, used to prove that another Keymaster HAL has
+     *        verified some parameters, and to deliver the other HAL's current timestamp, if needed.
+     *        If not provided, all fields must be initialized to zero and vectors empty.
+     *
+     * @return error See the ErrorCode enum in types.hal.
+     *
+     * @return outParams Any output parameters generated by finish().
+     *
+     * @return output The output data, if any.
+     */
+    finish(OperationHandle operationHandle, vec<KeyParameter> inParams, vec<uint8_t> input,
+           vec<uint8_t> signature, HardwareAuthToken authToken, VerificationToken verificationToken)
+        generates (ErrorCode error, vec<KeyParameter> outParams, vec<uint8_t> output);
+
+    /**
+     * Aborts a cryptographic operation begun with begin(), freeing all internal resources and
+     * invalidating operationHandle.
+     *
+     * @param operationHandle The operation handle returned by begin().  This handle must be
+     *        invalid when abort() returns.
+     *
+     * @return error See the ErrorCode enum in types.hal.
+     */
+    abort(OperationHandle operationHandle) generates (ErrorCode error);
+};
diff --git a/keymaster/4.0/default/Android.bp b/keymaster/4.0/default/Android.bp
new file mode 100644
index 0000000..0cede50
--- /dev/null
+++ b/keymaster/4.0/default/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+    name: "android.hardware.keymaster@4.0-service",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.keymaster@4.0-service.rc"],
+    srcs: ["service.cpp"],
+
+    shared_libs: [
+        "android.hardware.keymaster@4.0",
+        "libbase",
+        "libcutils",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "libkeymaster4",
+        "liblog",
+        "libutils",
+    ],
+
+}
diff --git a/keymaster/4.0/default/OWNERS b/keymaster/4.0/default/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/keymaster/4.0/default/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc b/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc
new file mode 100644
index 0000000..2ce439e
--- /dev/null
+++ b/keymaster/4.0/default/android.hardware.keymaster@4.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.keymaster-4-0 /vendor/bin/hw/android.hardware.keymaster@4.0-service
+    class early_hal
+    user system
+    group system drmrpc
diff --git a/keymaster/4.0/default/service.cpp b/keymaster/4.0/default/service.cpp
new file mode 100644
index 0000000..cfb960a
--- /dev/null
+++ b/keymaster/4.0/default/service.cpp
@@ -0,0 +1,35 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <android-base/logging.h>
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <AndroidKeymaster4Device.h>
+
+using android::hardware::keymaster::V4_0::SecurityLevel;
+
+int main() {
+    auto keymaster = ::keymaster::V4_0::ng::CreateKeymasterDevice(SecurityLevel::SOFTWARE);
+    auto status = keymaster->registerAsService();
+    if (status != android::OK) {
+        LOG(FATAL) << "Could not register service for Keymaster 4.0 (" << status << ")";
+    }
+
+    android::hardware::joinRpcThreadpool();
+    return -1;  // Should never get here.
+}
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
new file mode 100644
index 0000000..ccd1b56
--- /dev/null
+++ b/keymaster/4.0/support/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library {
+    name: "libkeymaster4support",
+    vendor_available: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "attestation_record.cpp",
+        "authorization_set.cpp",
+        "key_param_output.cpp",
+        "keymaster_utils.cpp",
+        "Keymaster.cpp",
+        "Keymaster3.cpp",
+        "Keymaster4.cpp",
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "android.hardware.keymaster@3.0",
+        "android.hardware.keymaster@4.0",
+        "libbase",
+        "libcrypto",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "libutils",
+    ]
+}
diff --git a/keymaster/4.0/support/Keymaster.cpp b/keymaster/4.0/support/Keymaster.cpp
new file mode 100644
index 0000000..bf52c47
--- /dev/null
+++ b/keymaster/4.0/support/Keymaster.cpp
@@ -0,0 +1,90 @@
+/*
+ ** Copyright 2018, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <keymasterV4_0/Keymaster.h>
+
+#include <android-base/logging.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <keymasterV4_0/Keymaster3.h>
+#include <keymasterV4_0/Keymaster4.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using ::android::sp;
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+template <typename Wrapper>
+std::vector<std::unique_ptr<Keymaster>> enumerateDevices(
+    const sp<IServiceManager>& serviceManager) {
+    std::vector<std::unique_ptr<Keymaster>> result;
+
+    bool foundDefault = false;
+    auto& descriptor = Wrapper::WrappedIKeymasterDevice::descriptor;
+    serviceManager->listByInterface(descriptor, [&](const hidl_vec<hidl_string>& names) {
+        for (auto& name : names) {
+            if (name == "default") foundDefault = true;
+            auto device = Wrapper::WrappedIKeymasterDevice::getService();
+            CHECK(device) << "Failed to get service for " << descriptor << " with interface name "
+                          << name;
+            result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, name)));
+        }
+    });
+
+    if (!foundDefault) {
+        // "default" wasn't provided by listByInterface.  Maybe there's a passthrough
+        // implementation.
+        auto device = Wrapper::WrappedIKeymasterDevice::getService("default");
+        if (device) result.push_back(std::unique_ptr<Keymaster>(new Wrapper(device, "default")));
+    }
+
+    return result;
+}
+
+std::vector<std::unique_ptr<Keymaster>> Keymaster::enumerateAvailableDevices() {
+    auto serviceManager = IServiceManager::getService();
+    CHECK(serviceManager) << "Could not retrieve ServiceManager";
+
+    auto km4s = enumerateDevices<Keymaster4>(serviceManager);
+    auto km3s = enumerateDevices<Keymaster3>(serviceManager);
+
+    auto result = std::move(km4s);
+    result.insert(result.end(), std::make_move_iterator(km3s.begin()),
+                  std::make_move_iterator(km3s.end()));
+
+    std::sort(result.begin(), result.end(),
+              [](auto& a, auto& b) { return a->halVersion() > b->halVersion(); });
+
+    size_t i = 1;
+    LOG(INFO) << "List of Keymaster HALs found:";
+    for (auto& hal : result) {
+        auto& version = hal->halVersion();
+        LOG(INFO) << "Keymaster HAL #" << i << ": " << version.keymasterName << " from "
+                  << version.authorName << " SecurityLevel: " << toString(version.securityLevel)
+                  << " HAL : " << hal->descriptor() << " instance " << hal->instanceName();
+    }
+
+    return result;
+}
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+};  // namespace android
diff --git a/keymaster/4.0/support/Keymaster3.cpp b/keymaster/4.0/support/Keymaster3.cpp
new file mode 100644
index 0000000..b2cdbd9
--- /dev/null
+++ b/keymaster/4.0/support/Keymaster3.cpp
@@ -0,0 +1,291 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <keymasterV4_0/Keymaster3.h>
+
+#include <android-base/logging.h>
+#include <keymasterV4_0/keymaster_utils.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using android::hardware::details::StatusOf;
+
+namespace {
+
+ErrorCode convert(V3_0::ErrorCode error) {
+    return static_cast<ErrorCode>(error);
+}
+
+V3_0::KeyPurpose convert(KeyPurpose purpose) {
+    return static_cast<V3_0::KeyPurpose>(purpose);
+}
+
+V3_0::KeyFormat convert(KeyFormat purpose) {
+    return static_cast<V3_0::KeyFormat>(purpose);
+}
+
+V3_0::KeyParameter convert(const KeyParameter& param) {
+    V3_0::KeyParameter converted;
+    converted.tag = static_cast<V3_0::Tag>(param.tag);
+    static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
+    memcpy(&converted.f, &param.f, sizeof(param.f));
+    converted.blob = param.blob;
+    return converted;
+}
+
+KeyParameter convert(const V3_0::KeyParameter& param) {
+    KeyParameter converted;
+    converted.tag = static_cast<Tag>(param.tag);
+    static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
+    memcpy(&converted.f, &param.f, sizeof(param.f));
+    converted.blob = param.blob;
+    return converted;
+}
+
+hidl_vec<V3_0::KeyParameter> convert(const hidl_vec<KeyParameter>& params) {
+    hidl_vec<V3_0::KeyParameter> converted(params.size());
+    for (size_t i = 0; i < params.size(); ++i) {
+        converted[i] = convert(params[i]);
+    }
+    return converted;
+}
+
+hidl_vec<KeyParameter> convert(const hidl_vec<V3_0::KeyParameter>& params) {
+    hidl_vec<KeyParameter> converted(params.size());
+    for (size_t i = 0; i < params.size(); ++i) {
+        converted[i] = convert(params[i]);
+    }
+    return converted;
+}
+
+template <typename T, typename OutIter>
+inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
+    const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
+    return std::copy(value_ptr, value_ptr + sizeof(value), dest);
+}
+
+hidl_vec<V3_0::KeyParameter> convertAndAddAuthToken(const hidl_vec<KeyParameter>& params,
+                                                    const HardwareAuthToken& authToken) {
+    hidl_vec<V3_0::KeyParameter> converted(params.size() + 1);
+    for (size_t i = 0; i < params.size(); ++i) {
+        converted[i] = convert(params[i]);
+    }
+    converted[params.size()].tag = V3_0::Tag::AUTH_TOKEN;
+    converted[params.size()].blob = authToken2HidlVec(authToken);
+
+    return converted;
+}
+
+KeyCharacteristics convert(const V3_0::KeyCharacteristics& chars) {
+    KeyCharacteristics converted;
+    converted.hardwareEnforced = convert(chars.teeEnforced);
+    converted.softwareEnforced = convert(chars.softwareEnforced);
+    return converted;
+}
+
+}  // namespace
+
+void Keymaster3::getVersionIfNeeded() {
+    if (haveVersion_) return;
+
+    auto rc = km3_dev_->getHardwareFeatures(
+        [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
+            bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
+            const hidl_string& keymasterAuthorName) {
+            version_ = {keymasterName, keymasterAuthorName, 0 /* major version, filled below */,
+                        isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE,
+                        supportsEllipticCurve};
+            supportsSymmetricCryptography_ = supportsSymmetricCryptography;
+            supportsAttestation_ = supportsAttestation;
+            supportsAllDigests_ = supportsAllDigests;
+        });
+
+    CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
+
+    if (version_.securityLevel == SecurityLevel::SOFTWARE) {
+        version_.majorVersion = 3;
+    } else if (supportsAttestation_) {
+        version_.majorVersion = 3;  // Could be 2, doesn't matter.
+    } else if (supportsSymmetricCryptography_) {
+        version_.majorVersion = 1;
+    } else {
+        version_.majorVersion = 0;
+    }
+}
+
+Return<void> Keymaster3::getHardwareInfo(Keymaster3::getHardwareInfo_cb _hidl_cb) {
+    getVersionIfNeeded();
+    _hidl_cb(version_.securityLevel,
+             std::string(version_.keymasterName) + " (wrapped by keystore::Keymaster3)",
+             version_.authorName);
+    return Void();
+}
+
+Return<ErrorCode> Keymaster3::addRngEntropy(const hidl_vec<uint8_t>& data) {
+    auto rc = km3_dev_->addRngEntropy(data);
+    if (!rc.isOk()) {
+        return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    }
+    return convert(rc);
+}
+
+Return<void> Keymaster3::generateKey(const hidl_vec<KeyParameter>& keyParams,
+                                     generateKey_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
+                  const V3_0::KeyCharacteristics& characteristics) {
+        _hidl_cb(convert(error), keyBlob, convert(characteristics));
+    };
+    auto rc = km3_dev_->generateKey(convert(keyParams), cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                               const hidl_vec<uint8_t>& clientId,
+                                               const hidl_vec<uint8_t>& appData,
+                                               getKeyCharacteristics_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const V3_0::KeyCharacteristics& chars) {
+        _hidl_cb(convert(error), convert(chars));
+    };
+
+    auto rc = km3_dev_->getKeyCharacteristics(keyBlob, clientId, appData, cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+                                   const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
+                  const V3_0::KeyCharacteristics& chars) {
+        _hidl_cb(convert(error), keyBlob, convert(chars));
+    };
+    auto rc = km3_dev_->importKey(convert(params), convert(keyFormat), keyData, cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+                                   const hidl_vec<uint8_t>& clientId,
+                                   const hidl_vec<uint8_t>& appData, exportKey_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyMaterial) {
+        _hidl_cb(convert(error), keyMaterial);
+    };
+    auto rc = km3_dev_->exportKey(convert(exportFormat), keyBlob, clientId, appData, cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                                   const hidl_vec<KeyParameter>& attestParams,
+                                   attestKey_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
+        _hidl_cb(convert(error), certChain);
+    };
+    auto rc = km3_dev_->attestKey(keyToAttest, convert(attestParams), cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                                    const hidl_vec<KeyParameter>& upgradeParams,
+                                    upgradeKey_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& upgradedKeyBlob) {
+        _hidl_cb(convert(error), upgradedKeyBlob);
+    };
+    auto rc = km3_dev_->upgradeKey(keyBlobToUpgrade, convert(upgradeParams), cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<ErrorCode> Keymaster3::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+    auto rc = km3_dev_->deleteKey(keyBlob);
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    return convert(rc);
+}
+
+Return<ErrorCode> Keymaster3::deleteAllKeys() {
+    auto rc = km3_dev_->deleteAllKeys();
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    return convert(rc);
+}
+
+Return<ErrorCode> Keymaster3::destroyAttestationIds() {
+    auto rc = km3_dev_->destroyAttestationIds();
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    return convert(rc);
+}
+
+Return<void> Keymaster3::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                               const hidl_vec<KeyParameter>& inParams,
+                               const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<V3_0::KeyParameter>& outParams,
+                  OperationHandle operationHandle) {
+        _hidl_cb(convert(error), convert(outParams), operationHandle);
+    };
+
+    auto rc =
+        km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                                const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+                                const VerificationToken& /* verificationToken */,
+                                update_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, uint32_t inputConsumed,
+                  const hidl_vec<V3_0::KeyParameter>& outParams, const hidl_vec<uint8_t>& output) {
+        _hidl_cb(convert(error), inputConsumed, convert(outParams), output);
+    };
+
+    auto rc =
+        km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input, cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                                const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+                                const HardwareAuthToken& authToken,
+                                const VerificationToken& /* verificationToken */,
+                                finish_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<V3_0::KeyParameter>& outParams,
+                  const hidl_vec<uint8_t>& output) {
+        _hidl_cb(convert(error), convert(outParams), output);
+    };
+
+    auto rc = km3_dev_->finish(operationHandle, convertAndAddAuthToken(inParams, authToken), input,
+                               signature, cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
+    auto rc = km3_dev_->abort(operationHandle);
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    return convert(rc);
+}
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/support/Keymaster4.cpp b/keymaster/4.0/support/Keymaster4.cpp
new file mode 100644
index 0000000..cc3d656
--- /dev/null
+++ b/keymaster/4.0/support/Keymaster4.cpp
@@ -0,0 +1,46 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <keymasterV4_0/Keymaster4.h>
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+void Keymaster4::getVersionIfNeeded() {
+    if (haveVersion_) return;
+
+    auto rc =
+        dev_->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& keymasterName,
+                                  const hidl_string& authorName) {
+            version_ = {keymasterName, authorName, 4 /* major version */, securityLevel,
+                        true /* supportsEc */};
+            haveVersion_ = true;
+        });
+
+    CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
+}
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/support/OWNERS b/keymaster/4.0/support/OWNERS
new file mode 100644
index 0000000..335660d
--- /dev/null
+++ b/keymaster/4.0/support/OWNERS
@@ -0,0 +1,2 @@
+jdanis@google.com
+swillden@google.com
diff --git a/keymaster/4.0/support/attestation_record.cpp b/keymaster/4.0/support/attestation_record.cpp
new file mode 100644
index 0000000..8f37d9c
--- /dev/null
+++ b/keymaster/4.0/support/attestation_record.cpp
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymasterV4_0/attestation_record.h>
+
+#include <assert.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <keymasterV4_0/authorization_set.h>
+#include <keymasterV4_0/openssl_utils.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+struct stack_st_ASN1_TYPE_Delete {
+    void operator()(stack_st_ASN1_TYPE* p) { sk_ASN1_TYPE_free(p); }
+};
+
+struct ASN1_STRING_Delete {
+    void operator()(ASN1_STRING* p) { ASN1_STRING_free(p); }
+};
+
+struct ASN1_TYPE_Delete {
+    void operator()(ASN1_TYPE* p) { ASN1_TYPE_free(p); }
+};
+
+#define ASN1_INTEGER_SET STACK_OF(ASN1_INTEGER)
+
+typedef struct km_root_of_trust {
+    ASN1_OCTET_STRING* verified_boot_key;
+    ASN1_BOOLEAN* device_locked;
+    ASN1_ENUMERATED* verified_boot_state;
+} KM_ROOT_OF_TRUST;
+
+ASN1_SEQUENCE(KM_ROOT_OF_TRUST) = {
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_key, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, device_locked, ASN1_BOOLEAN),
+    ASN1_SIMPLE(KM_ROOT_OF_TRUST, verified_boot_state, ASN1_ENUMERATED),
+} ASN1_SEQUENCE_END(KM_ROOT_OF_TRUST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ROOT_OF_TRUST);
+
+typedef struct km_auth_list {
+    ASN1_INTEGER_SET* purpose;
+    ASN1_INTEGER* algorithm;
+    ASN1_INTEGER* key_size;
+    ASN1_INTEGER_SET* digest;
+    ASN1_INTEGER_SET* padding;
+    ASN1_INTEGER* ec_curve;
+    ASN1_INTEGER* rsa_public_exponent;
+    ASN1_INTEGER* active_date_time;
+    ASN1_INTEGER* origination_expire_date_time;
+    ASN1_INTEGER* usage_expire_date_time;
+    ASN1_NULL* no_auth_required;
+    ASN1_INTEGER* user_auth_type;
+    ASN1_INTEGER* auth_timeout;
+    ASN1_NULL* allow_while_on_body;
+    ASN1_NULL* all_applications;
+    ASN1_OCTET_STRING* application_id;
+    ASN1_INTEGER* creation_date_time;
+    ASN1_INTEGER* origin;
+    ASN1_NULL* rollback_resistant;
+    KM_ROOT_OF_TRUST* root_of_trust;
+    ASN1_INTEGER* os_version;
+    ASN1_INTEGER* os_patchlevel;
+    ASN1_OCTET_STRING* attestation_application_id;
+} KM_AUTH_LIST;
+
+ASN1_SEQUENCE(KM_AUTH_LIST) = {
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, purpose, ASN1_INTEGER, TAG_PURPOSE.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, algorithm, ASN1_INTEGER, TAG_ALGORITHM.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, key_size, ASN1_INTEGER, TAG_KEY_SIZE.maskedTag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, digest, ASN1_INTEGER, TAG_DIGEST.maskedTag()),
+    ASN1_EXP_SET_OF_OPT(KM_AUTH_LIST, padding, ASN1_INTEGER, TAG_PADDING.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, ec_curve, ASN1_INTEGER, TAG_EC_CURVE.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, rsa_public_exponent, ASN1_INTEGER,
+                 TAG_RSA_PUBLIC_EXPONENT.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, active_date_time, ASN1_INTEGER, TAG_ACTIVE_DATETIME.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, origination_expire_date_time, ASN1_INTEGER,
+                 TAG_ORIGINATION_EXPIRE_DATETIME.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, usage_expire_date_time, ASN1_INTEGER,
+                 TAG_USAGE_EXPIRE_DATETIME.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, no_auth_required, ASN1_NULL, TAG_NO_AUTH_REQUIRED.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, user_auth_type, ASN1_INTEGER, TAG_USER_AUTH_TYPE.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, auth_timeout, ASN1_INTEGER, TAG_AUTH_TIMEOUT.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, allow_while_on_body, ASN1_NULL, TAG_ALLOW_WHILE_ON_BODY.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, application_id, ASN1_OCTET_STRING, TAG_APPLICATION_ID.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, creation_date_time, ASN1_INTEGER, TAG_CREATION_DATETIME.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, origin, ASN1_INTEGER, TAG_ORIGIN.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, rollback_resistant, ASN1_NULL, TAG_ROLLBACK_RESISTANCE.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, root_of_trust, KM_ROOT_OF_TRUST, TAG_ROOT_OF_TRUST.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, os_version, ASN1_INTEGER, TAG_OS_VERSION.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, os_patchlevel, ASN1_INTEGER, TAG_OS_PATCHLEVEL.maskedTag()),
+    ASN1_EXP_OPT(KM_AUTH_LIST, attestation_application_id, ASN1_OCTET_STRING,
+                 TAG_ATTESTATION_APPLICATION_ID.maskedTag()),
+} ASN1_SEQUENCE_END(KM_AUTH_LIST);
+IMPLEMENT_ASN1_FUNCTIONS(KM_AUTH_LIST);
+
+typedef struct km_key_description {
+    ASN1_INTEGER* attestation_version;
+    ASN1_ENUMERATED* attestation_security_level;
+    ASN1_INTEGER* keymaster_version;
+    ASN1_ENUMERATED* keymaster_security_level;
+    ASN1_OCTET_STRING* attestation_challenge;
+    KM_AUTH_LIST* software_enforced;
+    KM_AUTH_LIST* tee_enforced;
+    ASN1_INTEGER* unique_id;
+} KM_KEY_DESCRIPTION;
+
+ASN1_SEQUENCE(KM_KEY_DESCRIPTION) = {
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_version, ASN1_INTEGER),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_security_level, ASN1_ENUMERATED),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_version, ASN1_INTEGER),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, keymaster_security_level, ASN1_ENUMERATED),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, attestation_challenge, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, unique_id, ASN1_OCTET_STRING),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, software_enforced, KM_AUTH_LIST),
+    ASN1_SIMPLE(KM_KEY_DESCRIPTION, tee_enforced, KM_AUTH_LIST),
+} ASN1_SEQUENCE_END(KM_KEY_DESCRIPTION);
+IMPLEMENT_ASN1_FUNCTIONS(KM_KEY_DESCRIPTION);
+
+template <Tag tag>
+void copyAuthTag(const stack_st_ASN1_INTEGER* stack, TypedTag<TagType::ENUM_REP, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT;
+    for (size_t i = 0; i < sk_ASN1_INTEGER_num(stack); ++i) {
+        auth_list->push_back(
+            ttag, static_cast<ValueT>(ASN1_INTEGER_get(sk_ASN1_INTEGER_value(stack, i))));
+    }
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ENUM, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    typedef typename TypedTag2ValueType<decltype(ttag)>::type ValueT;
+    if (!asn1_int) return;
+    auth_list->push_back(ttag, static_cast<ValueT>(ASN1_INTEGER_get(asn1_int)));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::UINT, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    auth_list->push_back(ttag, ASN1_INTEGER_get(asn1_int));
+}
+
+BIGNUM* construct_uint_max() {
+    BIGNUM* value = BN_new();
+    BIGNUM_Ptr one(BN_new());
+    BN_one(one.get());
+    BN_lshift(value, one.get(), 32);
+    return value;
+}
+
+uint64_t BignumToUint64(BIGNUM* num) {
+    static_assert((sizeof(BN_ULONG) == sizeof(uint32_t)) || (sizeof(BN_ULONG) == sizeof(uint64_t)),
+                  "This implementation only supports 32 and 64-bit BN_ULONG");
+    if (sizeof(BN_ULONG) == sizeof(uint32_t)) {
+        BIGNUM_Ptr uint_max(construct_uint_max());
+        BIGNUM_Ptr hi(BN_new()), lo(BN_new());
+        BN_CTX_Ptr ctx(BN_CTX_new());
+        BN_div(hi.get(), lo.get(), num, uint_max.get(), ctx.get());
+        return static_cast<uint64_t>(BN_get_word(hi.get())) << 32 | BN_get_word(lo.get());
+    } else if (sizeof(BN_ULONG) == sizeof(uint64_t)) {
+        return BN_get_word(num);
+    } else {
+        return 0;
+    }
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::ULONG, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+    auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_INTEGER* asn1_int, TypedTag<TagType::DATE, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_int) return;
+    BIGNUM_Ptr num(ASN1_INTEGER_to_BN(asn1_int, nullptr));
+    auth_list->push_back(ttag, BignumToUint64(num.get()));
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_NULL* asn1_null, TypedTag<TagType::BOOL, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_null) return;
+    auth_list->push_back(ttag);
+}
+
+template <Tag tag>
+void copyAuthTag(const ASN1_OCTET_STRING* asn1_string, TypedTag<TagType::BYTES, tag> ttag,
+                 AuthorizationSet* auth_list) {
+    if (!asn1_string) return;
+    hidl_vec<uint8_t> buf;
+    buf.setToExternal(asn1_string->data, asn1_string->length);
+    auth_list->push_back(ttag, buf);
+}
+
+// Extract the values from the specified ASN.1 record and place them in auth_list.
+static ErrorCode extract_auth_list(const KM_AUTH_LIST* record, AuthorizationSet* auth_list) {
+    if (!record) return ErrorCode::OK;
+
+    copyAuthTag(record->active_date_time, TAG_ACTIVE_DATETIME, auth_list);
+    copyAuthTag(record->algorithm, TAG_ALGORITHM, auth_list);
+    copyAuthTag(record->application_id, TAG_APPLICATION_ID, auth_list);
+    copyAuthTag(record->auth_timeout, TAG_AUTH_TIMEOUT, auth_list);
+    copyAuthTag(record->creation_date_time, TAG_CREATION_DATETIME, auth_list);
+    copyAuthTag(record->digest, TAG_DIGEST, auth_list);
+    copyAuthTag(record->ec_curve, TAG_EC_CURVE, auth_list);
+    copyAuthTag(record->key_size, TAG_KEY_SIZE, auth_list);
+    copyAuthTag(record->no_auth_required, TAG_NO_AUTH_REQUIRED, auth_list);
+    copyAuthTag(record->origin, TAG_ORIGIN, auth_list);
+    copyAuthTag(record->origination_expire_date_time, TAG_ORIGINATION_EXPIRE_DATETIME, auth_list);
+    copyAuthTag(record->os_patchlevel, TAG_OS_PATCHLEVEL, auth_list);
+    copyAuthTag(record->os_version, TAG_OS_VERSION, auth_list);
+    copyAuthTag(record->padding, TAG_PADDING, auth_list);
+    copyAuthTag(record->purpose, TAG_PURPOSE, auth_list);
+    copyAuthTag(record->rollback_resistant, TAG_ROLLBACK_RESISTANCE, auth_list);
+    copyAuthTag(record->rsa_public_exponent, TAG_RSA_PUBLIC_EXPONENT, auth_list);
+    copyAuthTag(record->usage_expire_date_time, TAG_USAGE_EXPIRE_DATETIME, auth_list);
+    copyAuthTag(record->user_auth_type, TAG_USER_AUTH_TYPE, auth_list);
+    copyAuthTag(record->attestation_application_id, TAG_ATTESTATION_APPLICATION_ID, auth_list);
+
+    return ErrorCode::OK;
+}
+
+MAKE_OPENSSL_PTR_TYPE(KM_KEY_DESCRIPTION)
+
+// Parse the DER-encoded attestation record, placing the results in keymaster_version,
+// attestation_challenge, software_enforced, tee_enforced and unique_id.
+ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                   uint32_t* attestation_version,  //
+                                   SecurityLevel* attestation_security_level,
+                                   uint32_t* keymaster_version,
+                                   SecurityLevel* keymaster_security_level,
+                                   hidl_vec<uint8_t>* attestation_challenge,
+                                   AuthorizationSet* software_enforced,
+                                   AuthorizationSet* tee_enforced,  //
+                                   hidl_vec<uint8_t>* unique_id) {
+    const uint8_t* p = asn1_key_desc;
+    KM_KEY_DESCRIPTION_Ptr record(d2i_KM_KEY_DESCRIPTION(nullptr, &p, asn1_key_desc_len));
+    if (!record.get()) return ErrorCode::UNKNOWN_ERROR;
+
+    *attestation_version = ASN1_INTEGER_get(record->attestation_version);
+    *attestation_security_level =
+        static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->attestation_security_level));
+    *keymaster_version = ASN1_INTEGER_get(record->keymaster_version);
+    *keymaster_security_level =
+        static_cast<SecurityLevel>(ASN1_ENUMERATED_get(record->keymaster_security_level));
+
+    auto& chall = record->attestation_challenge;
+    attestation_challenge->resize(chall->length);
+    memcpy(attestation_challenge->data(), chall->data, chall->length);
+    auto& uid = record->unique_id;
+    unique_id->resize(uid->length);
+    memcpy(unique_id->data(), uid->data, uid->length);
+
+    ErrorCode error = extract_auth_list(record->software_enforced, software_enforced);
+    if (error != ErrorCode::OK) return error;
+
+    return extract_auth_list(record->tee_enforced, tee_enforced);
+}
+
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
new file mode 100644
index 0000000..bf77420
--- /dev/null
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -0,0 +1,545 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymasterV4_0/authorization_set.h>
+
+#include <assert.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
+    if (a.tag != b.tag) return a.tag < b.tag;
+    int retval;
+    switch (typeFromTag(a.tag)) {
+        case TagType::INVALID:
+        case TagType::BOOL:
+            return false;
+        case TagType::ENUM:
+        case TagType::ENUM_REP:
+        case TagType::UINT:
+        case TagType::UINT_REP:
+            return a.f.integer < b.f.integer;
+        case TagType::ULONG:
+        case TagType::ULONG_REP:
+            return a.f.longInteger < b.f.longInteger;
+        case TagType::DATE:
+            return a.f.dateTime < b.f.dateTime;
+        case TagType::BIGNUM:
+        case TagType::BYTES:
+            // Handle the empty cases.
+            if (a.blob.size() == 0) return b.blob.size() != 0;
+            if (b.blob.size() == 0) return false;
+
+            retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+            // if one is the prefix of the other the longer wins
+            if (retval == 0) return a.blob.size() < b.blob.size();
+            // Otherwise a is less if a is less.
+            else
+                return retval < 0;
+    }
+    return false;
+}
+
+inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
+    if (a.tag != b.tag) return false;
+
+    switch (typeFromTag(a.tag)) {
+        case TagType::INVALID:
+        case TagType::BOOL:
+            return true;
+        case TagType::ENUM:
+        case TagType::ENUM_REP:
+        case TagType::UINT:
+        case TagType::UINT_REP:
+            return a.f.integer == b.f.integer;
+        case TagType::ULONG:
+        case TagType::ULONG_REP:
+            return a.f.longInteger == b.f.longInteger;
+        case TagType::DATE:
+            return a.f.dateTime == b.f.dateTime;
+        case TagType::BIGNUM:
+        case TagType::BYTES:
+            if (a.blob.size() != b.blob.size()) return false;
+            return a.blob.size() == 0 || memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
+    }
+    return false;
+}
+
+void AuthorizationSet::Sort() {
+    std::sort(data_.begin(), data_.end(), keyParamLess);
+}
+
+void AuthorizationSet::Deduplicate() {
+    if (data_.empty()) return;
+
+    Sort();
+    std::vector<KeyParameter> result;
+
+    auto curr = data_.begin();
+    auto prev = curr++;
+    for (; curr != data_.end(); ++prev, ++curr) {
+        if (prev->tag == Tag::INVALID) continue;
+
+        if (!keyParamEqual(*prev, *curr)) {
+            result.emplace_back(std::move(*prev));
+        }
+    }
+    result.emplace_back(std::move(*prev));
+
+    std::swap(data_, result);
+}
+
+void AuthorizationSet::Union(const AuthorizationSet& other) {
+    data_.insert(data_.end(), other.data_.begin(), other.data_.end());
+    Deduplicate();
+}
+
+void AuthorizationSet::Subtract(const AuthorizationSet& other) {
+    Deduplicate();
+
+    auto i = other.begin();
+    while (i != other.end()) {
+        int pos = -1;
+        do {
+            pos = find(i->tag, pos);
+            if (pos != -1 && keyParamEqual(*i, data_[pos])) {
+                data_.erase(data_.begin() + pos);
+                break;
+            }
+        } while (pos != -1);
+        ++i;
+    }
+}
+
+KeyParameter& AuthorizationSet::operator[](int at) {
+    return data_[at];
+}
+
+const KeyParameter& AuthorizationSet::operator[](int at) const {
+    return data_[at];
+}
+
+void AuthorizationSet::Clear() {
+    data_.clear();
+}
+
+size_t AuthorizationSet::GetTagCount(Tag tag) const {
+    size_t count = 0;
+    for (int pos = -1; (pos = find(tag, pos)) != -1;) ++count;
+    return count;
+}
+
+int AuthorizationSet::find(Tag tag, int begin) const {
+    auto iter = data_.begin() + (1 + begin);
+
+    while (iter != data_.end() && iter->tag != tag) ++iter;
+
+    if (iter != data_.end()) return iter - data_.begin();
+    return -1;
+}
+
+bool AuthorizationSet::erase(int index) {
+    auto pos = data_.begin() + index;
+    if (pos != data_.end()) {
+        data_.erase(pos);
+        return true;
+    }
+    return false;
+}
+
+NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
+    int pos = find(tag);
+    if (pos == -1) return {};
+    return data_[pos];
+}
+
+/**
+ * Persistent format is:
+ * | 32 bit indirect_size         |
+ * --------------------------------
+ * | indirect_size bytes of data  | this is where the blob data is stored
+ * --------------------------------
+ * | 32 bit element_count         | number of entries
+ * | 32 bit elements_size         | total bytes used by entries (entries have variable length)
+ * --------------------------------
+ * | elementes_size bytes of data | where the elements are stored
+ */
+
+/**
+ * Persistent format of blobs and bignums:
+ * | 32 bit tag             |
+ * | 32 bit blob_length     |
+ * | 32 bit indirect_offset |
+ */
+
+struct OutStreams {
+    std::ostream& indirect;
+    std::ostream& elements;
+};
+
+OutStreams& serializeParamValue(OutStreams& out, const hidl_vec<uint8_t>& blob) {
+    uint32_t buffer;
+
+    // write blob_length
+    auto blob_length = blob.size();
+    if (blob_length > std::numeric_limits<uint32_t>::max()) {
+        out.elements.setstate(std::ios_base::badbit);
+        return out;
+    }
+    buffer = blob_length;
+    out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+    // write indirect_offset
+    auto offset = out.indirect.tellp();
+    if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() ||
+        uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) {  // overflow check
+        out.elements.setstate(std::ios_base::badbit);
+        return out;
+    }
+    buffer = offset;
+    out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+    // write blob to indirect stream
+    if (blob_length) out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length);
+
+    return out;
+}
+
+template <typename T>
+OutStreams& serializeParamValue(OutStreams& out, const T& value) {
+    out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T));
+    return out;
+}
+
+OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
+    // skip invalid entries.
+    return out;
+}
+template <typename T>
+OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) {
+    out.elements.write(reinterpret_cast<const char*>(&param.tag), sizeof(int32_t));
+    return serializeParamValue(out, accessTagValue(ttag, param));
+}
+
+template <typename... T>
+struct choose_serializer;
+template <typename... Tags>
+struct choose_serializer<MetaList<Tags...>> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+        return choose_serializer<Tags...>::serialize(out, param);
+    }
+};
+
+template <>
+struct choose_serializer<> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter&) { return out; }
+};
+
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_serializer<TypedTag<tag_type, tag>, Tail...> {
+    static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+        if (param.tag == tag) {
+            return V4_0::serialize(TypedTag<tag_type, tag>(), out, param);
+        } else {
+            return choose_serializer<Tail...>::serialize(out, param);
+        }
+    }
+};
+
+OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+    return choose_serializer<all_tags_t>::serialize(out, param);
+}
+
+std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
+    std::stringstream indirect;
+    std::stringstream elements;
+    OutStreams streams = {indirect, elements};
+    for (const auto& param : params) {
+        serialize(streams, param);
+    }
+    if (indirect.bad() || elements.bad()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    auto pos = indirect.tellp();
+    if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    uint32_t indirect_size = pos;
+    pos = elements.tellp();
+    if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+        out.setstate(std::ios_base::badbit);
+        return out;
+    }
+    uint32_t elements_size = pos;
+    uint32_t element_count = params.size();
+
+    out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
+
+    pos = out.tellp();
+    if (indirect_size) out << indirect.rdbuf();
+    assert(out.tellp() - pos == indirect_size);
+
+    out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t));
+    out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t));
+
+    pos = out.tellp();
+    if (elements_size) out << elements.rdbuf();
+    assert(out.tellp() - pos == elements_size);
+
+    return out;
+}
+
+struct InStreams {
+    std::istream& indirect;
+    std::istream& elements;
+};
+
+InStreams& deserializeParamValue(InStreams& in, hidl_vec<uint8_t>* blob) {
+    uint32_t blob_length = 0;
+    uint32_t offset = 0;
+    in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t));
+    blob->resize(blob_length);
+    in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t));
+    in.indirect.seekg(offset);
+    in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size());
+    return in;
+}
+
+template <typename T>
+InStreams& deserializeParamValue(InStreams& in, T* value) {
+    in.elements.read(reinterpret_cast<char*>(value), sizeof(T));
+    return in;
+}
+
+InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
+    // there should be no invalid KeyParamaters but if handle them as zero sized.
+    return in;
+}
+
+template <typename T>
+InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) {
+    return deserializeParamValue(in, &accessTagValue(ttag, *param));
+}
+
+template <typename... T>
+struct choose_deserializer;
+template <typename... Tags>
+struct choose_deserializer<MetaList<Tags...>> {
+    static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+        return choose_deserializer<Tags...>::deserialize(in, param);
+    }
+};
+template <>
+struct choose_deserializer<> {
+    static InStreams& deserialize(InStreams& in, KeyParameter*) {
+        // encountered an unknown tag -> fail parsing
+        in.elements.setstate(std::ios_base::badbit);
+        return in;
+    }
+};
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> {
+    static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+        if (param->tag == tag) {
+            return V4_0::deserialize(TypedTag<tag_type, tag>(), in, param);
+        } else {
+            return choose_deserializer<Tail...>::deserialize(in, param);
+        }
+    }
+};
+
+InStreams& deserialize(InStreams& in, KeyParameter* param) {
+    in.elements.read(reinterpret_cast<char*>(&param->tag), sizeof(Tag));
+    return choose_deserializer<all_tags_t>::deserialize(in, param);
+}
+
+std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) {
+    uint32_t indirect_size = 0;
+    in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t));
+    std::string indirect_buffer(indirect_size, '\0');
+    if (indirect_buffer.size() != indirect_size) {
+        in.setstate(std::ios_base::badbit);
+        return in;
+    }
+    in.read(&indirect_buffer[0], indirect_buffer.size());
+
+    uint32_t element_count = 0;
+    in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t));
+    uint32_t elements_size = 0;
+    in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t));
+
+    std::string elements_buffer(elements_size, '\0');
+    if (elements_buffer.size() != elements_size) {
+        in.setstate(std::ios_base::badbit);
+        return in;
+    }
+    in.read(&elements_buffer[0], elements_buffer.size());
+
+    if (in.bad()) return in;
+
+    // TODO write one-shot stream buffer to avoid copying here
+    std::stringstream indirect(indirect_buffer);
+    std::stringstream elements(elements_buffer);
+    InStreams streams = {indirect, elements};
+
+    params->resize(element_count);
+
+    for (uint32_t i = 0; i < element_count; ++i) {
+        deserialize(streams, &(*params)[i]);
+    }
+    return in;
+}
+
+void AuthorizationSet::Serialize(std::ostream* out) const {
+    serialize(*out, data_);
+}
+
+void AuthorizationSet::Deserialize(std::istream* in) {
+    deserialize(*in, &data_);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size,
+                                                         uint64_t public_exponent) {
+    Authorization(TAG_ALGORITHM, Algorithm::RSA);
+    Authorization(TAG_KEY_SIZE, key_size);
+    Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
+    return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::EC);
+    Authorization(TAG_KEY_SIZE, key_size);
+    return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(EcCurve curve) {
+    Authorization(TAG_ALGORITHM, Algorithm::EC);
+    Authorization(TAG_EC_CURVE, curve);
+    return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::AES);
+    return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::TRIPLE_DES);
+    return Authorization(TAG_KEY_SIZE, key_size);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::HMAC);
+    Authorization(TAG_KEY_SIZE, key_size);
+    return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size,
+                                                                uint64_t public_exponent) {
+    RsaKey(key_size, public_exponent);
+    return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size,
+                                                                   uint64_t public_exponent) {
+    RsaKey(key_size, public_exponent);
+    return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) {
+    EcdsaKey(key_size);
+    return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(EcCurve curve) {
+    EcdsaKey(curve);
+    return SigningKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) {
+    AesKey(key_size);
+    return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesEncryptionKey(uint32_t key_size) {
+    TripleDesKey(key_size);
+    return EncryptionKey();
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
+    Authorization(TAG_PURPOSE, KeyPurpose::SIGN);
+    return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() {
+    Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT);
+    return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
+    Authorization(TAG_DIGEST, Digest::NONE);
+    return Authorization(TAG_PADDING, PaddingMode::NONE);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() {
+    return Authorization(TAG_BLOCK_MODE, BlockMode::ECB);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMinMacLen(uint32_t minMacLength) {
+    return BlockMode(BlockMode::GCM)
+        .Padding(PaddingMode::NONE)
+        .Authorization(TAG_MIN_MAC_LENGTH, minMacLength);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::GcmModeMacLen(uint32_t macLength) {
+    return BlockMode(BlockMode::GCM)
+        .Padding(PaddingMode::NONE)
+        .Authorization(TAG_MAC_LENGTH, macLength);
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::BlockMode(
+    std::initializer_list<V4_0::BlockMode> blockModes) {
+    for (auto mode : blockModes) {
+        push_back(TAG_BLOCK_MODE, mode);
+    }
+    return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::Digest(
+    std::initializer_list<V4_0::Digest> digests) {
+    for (auto digest : digests) {
+        push_back(TAG_DIGEST, digest);
+    }
+    return *this;
+}
+
+AuthorizationSetBuilder& AuthorizationSetBuilder::Padding(
+    std::initializer_list<V4_0::PaddingMode> paddingModes) {
+    for (auto paddingMode : paddingModes) {
+        push_back(TAG_PADDING, paddingMode);
+    }
+    return *this;
+}
+
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
new file mode 100644
index 0000000..f9efd51
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
@@ -0,0 +1,79 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
+
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+/**
+ * Keymaster abstracts the underlying V4_0::IKeymasterDevice.  There is one implementation
+ * (Keymaster4) which is a trivial passthrough and one that wraps a V3_0::IKeymasterDevice.
+ *
+ * The reason for adding this additional layer, rather than simply using the latest HAL directly and
+ * subclassing it to wrap any older HAL, is because this provides a place to put additional methods
+ * which clients can use when they need to distinguish between different underlying HAL versions,
+ * while still having to use only the latest interface.
+ */
+class Keymaster : public IKeymasterDevice {
+   public:
+    Keymaster(const hidl_string& descriptor, const hidl_string& instanceName)
+        : descriptor_(descriptor), instanceName_(instanceName) {}
+    virtual ~Keymaster() {}
+
+    struct VersionResult {
+        hidl_string keymasterName;
+        hidl_string authorName;
+        uint8_t majorVersion;
+        SecurityLevel securityLevel;
+        bool supportsEc;
+
+        bool operator>(const VersionResult& other) const {
+            auto lhs = std::tie(securityLevel, majorVersion, supportsEc);
+            auto rhs = std::tie(other.securityLevel, other.majorVersion, other.supportsEc);
+            return lhs > rhs;
+        }
+    };
+
+    virtual const VersionResult& halVersion() = 0;
+    const hidl_string& descriptor() { return descriptor_; }
+    const hidl_string& instanceName() { return instanceName_; }
+
+    /**
+     * Returns all available Keymaster3 and Keymaster4 instances, in order of most secure to least
+     * secure (as defined by VersionResult::operator<).
+     */
+    static std::vector<std::unique_ptr<Keymaster>> enumerateAvailableDevices();
+
+   private:
+    hidl_string descriptor_;
+    hidl_string instanceName_;
+};
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
new file mode 100644
index 0000000..2bb77ca
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
@@ -0,0 +1,135 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+
+#include "Keymaster.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using IKeymaster3Device = ::android::hardware::keymaster::V3_0::IKeymasterDevice;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::details::return_status;
+
+class Keymaster3 : public Keymaster {
+   public:
+    using WrappedIKeymasterDevice = IKeymaster3Device;
+    Keymaster3(sp<IKeymaster3Device> km3_dev, const hidl_string& instanceName)
+        : Keymaster(IKeymaster3Device::descriptor, instanceName),
+          km3_dev_(km3_dev),
+          haveVersion_(false) {}
+
+    const VersionResult& halVersion() override {
+        getVersionIfNeeded();
+        return version_;
+    }
+
+    Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb);
+
+    Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+        _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+        return Void();
+    }
+
+    Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>&,
+                                   computeSharedHmac_cb _hidl_cb) override {
+        _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+        return Void();
+    }
+
+    Return<void> verifyAuthorization(uint64_t, const hidl_vec<KeyParameter>&,
+                                     const HardwareAuthToken&,
+                                     verifyAuthorization_cb _hidl_cb) override {
+        _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+        return Void();
+    }
+
+    Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+                             generateKey_cb _hidl_cb) override;
+    Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                       const hidl_vec<uint8_t>& clientId,
+                                       const hidl_vec<uint8_t>& appData,
+                                       getKeyCharacteristics_cb _hidl_cb) override;
+    Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+                           const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
+
+    Return<void> importWrappedKey(const hidl_vec<uint8_t>& /* wrappedKeyData */,
+                                  const hidl_vec<uint8_t>& /* wrappingKeyBlob */,
+                                  const hidl_vec<uint8_t>& /* maskingKey */,
+                                  const hidl_vec<KeyParameter>& /* unwrappingParams */,
+                                  uint64_t /* passwordSid */, uint64_t /* biometricSid */,
+                                  importWrappedKey_cb _hidl_cb) {
+        _hidl_cb(ErrorCode::UNIMPLEMENTED, {}, {});
+        return Void();
+    }
+
+    Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+                           const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+                           exportKey_cb _hidl_cb) override;
+    Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                           const hidl_vec<KeyParameter>& attestParams,
+                           attestKey_cb _hidl_cb) override;
+    Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                            const hidl_vec<KeyParameter>& upgradeParams,
+                            upgradeKey_cb _hidl_cb) override;
+    Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+    Return<ErrorCode> deleteAllKeys() override;
+    Return<ErrorCode> destroyAttestationIds() override;
+    Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                       const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+                       begin_cb _hidl_cb) override;
+    Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, update_cb _hidl_cb) override;
+    Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+                        const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, finish_cb _hidl_cb) override;
+    Return<ErrorCode> abort(uint64_t operationHandle) override;
+
+   private:
+    void getVersionIfNeeded();
+
+    sp<IKeymaster3Device> km3_dev_;
+
+    bool haveVersion_;
+    VersionResult version_;
+    bool supportsSymmetricCryptography_;
+    bool supportsAttestation_;
+    bool supportsAllDigests_;
+};
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
new file mode 100644
index 0000000..96afb13
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
@@ -0,0 +1,160 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
+
+#include "Keymaster.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using android::sp;
+using IKeymaster4Device = ::android::hardware::keymaster::V4_0::IKeymasterDevice;
+
+class Keymaster4 : public Keymaster {
+   public:
+    using WrappedIKeymasterDevice = IKeymaster4Device;
+    Keymaster4(sp<IKeymasterDevice> km4_dev, const hidl_string& instanceName)
+        : Keymaster(IKeymaster4Device::descriptor, instanceName),
+          haveVersion_(false),
+          dev_(km4_dev) {}
+
+    const VersionResult& halVersion() override {
+        getVersionIfNeeded();
+        return version_;
+    }
+
+    Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
+        return dev_->getHardwareInfo(_hidl_cb);
+    }
+
+    Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+        return dev_->getHmacSharingParameters(_hidl_cb);
+    }
+
+    Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
+                                   computeSharedHmac_cb _hidl_cb) override {
+        return dev_->computeSharedHmac(params, _hidl_cb);
+    }
+
+    Return<void> verifyAuthorization(uint64_t operationHandle, const hidl_vec<KeyParameter>& params,
+                                     const HardwareAuthToken& authToken,
+                                     verifyAuthorization_cb _hidl_cb) override {
+        return dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb);
+    }
+
+    Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override {
+        return dev_->addRngEntropy(data);
+    }
+
+    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+                             generateKey_cb _hidl_cb) override {
+        return dev_->generateKey(keyParams, _hidl_cb);
+    }
+
+    Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                       const hidl_vec<uint8_t>& clientId,
+                                       const hidl_vec<uint8_t>& appData,
+                                       getKeyCharacteristics_cb _hidl_cb) override {
+        return dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb);
+    }
+
+    Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+                           const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override {
+        return dev_->importKey(params, keyFormat, keyData, _hidl_cb);
+    }
+
+    Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
+                                  const hidl_vec<uint8_t>& wrappingKeyBlob,
+                                  const hidl_vec<uint8_t>& maskingKey,
+                                  const hidl_vec<KeyParameter>& unwrappingParams,
+                                  uint64_t passwordSid, uint64_t biometricSid,
+                                  importWrappedKey_cb _hidl_cb) {
+        return dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey, unwrappingParams,
+                                      passwordSid, biometricSid, _hidl_cb);
+    }
+
+    Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+                           const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+                           exportKey_cb _hidl_cb) override {
+        return dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb);
+    }
+
+    Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                           const hidl_vec<KeyParameter>& attestParams,
+                           attestKey_cb _hidl_cb) override {
+        return dev_->attestKey(keyToAttest, attestParams, _hidl_cb);
+    }
+
+    Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                            const hidl_vec<KeyParameter>& upgradeParams,
+                            upgradeKey_cb _hidl_cb) override {
+        return dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb);
+    }
+
+    Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override {
+        return dev_->deleteKey(keyBlob);
+    }
+
+    Return<ErrorCode> deleteAllKeys() override { return dev_->deleteAllKeys(); }
+
+    Return<ErrorCode> destroyAttestationIds() override { return dev_->destroyAttestationIds(); }
+
+    Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                       const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+                       begin_cb _hidl_cb) override {
+        return dev_->begin(purpose, key, inParams, authToken, _hidl_cb);
+    }
+
+    Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, update_cb _hidl_cb) override {
+        return dev_->update(operationHandle, inParams, input, authToken, verificationToken,
+                            _hidl_cb);
+    }
+
+    Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+                        const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, finish_cb _hidl_cb) override {
+        return dev_->finish(operationHandle, inParams, input, signature, authToken,
+                            verificationToken, _hidl_cb);
+    }
+
+    Return<ErrorCode> abort(uint64_t operationHandle) override {
+        return dev_->abort(operationHandle);
+    }
+
+   private:
+    void getVersionIfNeeded();
+
+    bool haveVersion_;
+    VersionResult version_;
+    sp<IKeymaster4Device> dev_;
+};
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h b/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h
new file mode 100644
index 0000000..fae403a
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/attestation_record.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_ATTESTATION_RECORD_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_ATTESTATION_RECORD_H_
+
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+class AuthorizationSet;
+
+/**
+ * The OID for Android attestation records.  For the curious, it breaks down as follows:
+ *
+ * 1 = ISO
+ * 3 = org
+ * 6 = DoD (Huh? OIDs are weird.)
+ * 1 = IANA
+ * 4 = Private
+ * 1 = Enterprises
+ * 11129 = Google
+ * 2 = Google security
+ * 1 = certificate extension
+ * 17 = Android attestation extension.
+ */
+static const char kAttestionRecordOid[] = "1.3.6.1.4.1.11129.2.1.17";
+
+ErrorCode parse_attestation_record(const uint8_t* asn1_key_desc, size_t asn1_key_desc_len,
+                                   uint32_t* attestation_version,  //
+                                   SecurityLevel* attestation_security_level,
+                                   uint32_t* keymaster_version,
+                                   SecurityLevel* keymaster_security_level,
+                                   hidl_vec<uint8_t>* attestation_challenge,
+                                   AuthorizationSet* software_enforced,
+                                   AuthorizationSet* tee_enforced,  //
+                                   hidl_vec<uint8_t>* unique_id);
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_ATTESTATION_RECORD_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
new file mode 100644
index 0000000..6c7fd35
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
+#define SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
+
+#include <vector>
+
+#include <keymasterV4_0/keymaster_tags.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+class AuthorizationSetBuilder;
+
+/**
+ * An ordered collection of KeyParameters. It provides memory ownership and some convenient
+ * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters.
+ * For serialization, wrap the backing store of this structure in a hidl_vec<KeyParameter>.
+ */
+class AuthorizationSet {
+   public:
+    typedef KeyParameter value_type;
+
+    /**
+     * Construct an empty, dynamically-allocated, growable AuthorizationSet.
+     */
+    AuthorizationSet(){};
+
+    // Copy constructor.
+    AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {}
+
+    // Move constructor.
+    AuthorizationSet(AuthorizationSet&& other) : data_(std::move(other.data_)) {}
+
+    // Constructor from hidl_vec<KeyParameter>
+    AuthorizationSet(const hidl_vec<KeyParameter>& other) { *this = other; }
+
+    // Copy assignment.
+    AuthorizationSet& operator=(const AuthorizationSet& other) {
+        data_ = other.data_;
+        return *this;
+    }
+
+    // Move assignment.
+    AuthorizationSet& operator=(AuthorizationSet&& other) {
+        data_ = std::move(other.data_);
+        return *this;
+    }
+
+    AuthorizationSet& operator=(const hidl_vec<KeyParameter>& other) {
+        if (other.size() > 0) {
+            data_.resize(other.size());
+            for (size_t i = 0; i < data_.size(); ++i) {
+                /* This makes a deep copy even of embedded blobs.
+                 * See assignment operator/copy constructor of hidl_vec.*/
+                data_[i] = other[i];
+            }
+        }
+        return *this;
+    }
+
+    /**
+     * Clear existing authorization set data
+     */
+    void Clear();
+
+    ~AuthorizationSet() = default;
+
+    /**
+     * Returns the size of the set.
+     */
+    size_t size() const { return data_.size(); }
+
+    /**
+     * Returns true if the set is empty.
+     */
+    bool empty() const { return size() == 0; }
+
+    /**
+     * Returns the data in the set, directly. Be careful with this.
+     */
+    const KeyParameter* data() const { return data_.data(); }
+
+    /**
+     * Sorts the set
+     */
+    void Sort();
+
+    /**
+     * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the
+     * AuthorizationSetBuilder).
+     */
+    void Deduplicate();
+
+    /**
+     * Adds all elements from \p set that are not already present in this AuthorizationSet.  As a
+     * side-effect, if \p set is not null this AuthorizationSet will end up sorted.
+     */
+    void Union(const AuthorizationSet& set);
+
+    /**
+     * Removes all elements in \p set from this AuthorizationSet.
+     */
+    void Subtract(const AuthorizationSet& set);
+
+    /**
+     * Returns the offset of the next entry that matches \p tag, starting from the element after \p
+     * begin.  If not found, returns -1.
+     */
+    int find(Tag tag, int begin = -1) const;
+
+    /**
+     * Removes the entry at the specified index. Returns true if successful, false if the index was
+     * out of bounds.
+     */
+    bool erase(int index);
+
+    /**
+     * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration
+     */
+    std::vector<KeyParameter>::const_iterator begin() const { return data_.begin(); }
+
+    /**
+     * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration
+     */
+    std::vector<KeyParameter>::const_iterator end() const { return data_.end(); }
+
+    /**
+     * Returns the nth element of the set.
+     * Like for std::vector::operator[] there is no range check performed. Use of out of range
+     * indices is undefined.
+     */
+    KeyParameter& operator[](int n);
+
+    /**
+     * Returns the nth element of the set.
+     * Like for std::vector::operator[] there is no range check performed. Use of out of range
+     * indices is undefined.
+     */
+    const KeyParameter& operator[](int n) const;
+
+    /**
+     * Returns true if the set contains at least one instance of \p tag
+     */
+    bool Contains(Tag tag) const { return find(tag) != -1; }
+
+    template <TagType tag_type, Tag tag, typename ValueT>
+    bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const {
+        for (const auto& param : data_) {
+            auto entry = authorizationValue(ttag, param);
+            if (entry.isOk() && static_cast<ValueT>(entry.value()) == value) return true;
+        }
+        return false;
+    }
+    /**
+     * Returns the number of \p tag entries.
+     */
+    size_t GetTagCount(Tag tag) const;
+
+    template <typename T>
+    inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const {
+        auto entry = GetEntry(tag);
+        if (entry.isOk()) return authorizationValue(tag, entry.value());
+        return {};
+    }
+
+    void push_back(const KeyParameter& param) { data_.push_back(param); }
+    void push_back(KeyParameter&& param) { data_.push_back(std::move(param)); }
+    void push_back(const AuthorizationSet& set) {
+        for (auto& entry : set) {
+            push_back(entry);
+        }
+    }
+    void push_back(AuthorizationSet&& set) {
+        std::move(set.begin(), set.end(), std::back_inserter(*this));
+    }
+
+    /**
+     * Append the tag and enumerated value to the set.
+     * "val" may be exactly one parameter unless a boolean parameter is added.
+     * In this case "val" is omitted. This condition is checked at compile time by Authorization()
+     */
+    template <typename TypedTagT, typename... Value>
+    void push_back(TypedTagT tag, Value&&... val) {
+        push_back(Authorization(tag, std::forward<Value>(val)...));
+    }
+
+    template <typename Iterator>
+    void append(Iterator begin, Iterator end) {
+        while (begin != end) {
+            push_back(*begin);
+            ++begin;
+        }
+    }
+
+    hidl_vec<KeyParameter> hidl_data() const {
+        hidl_vec<KeyParameter> result;
+        result.setToExternal(const_cast<KeyParameter*>(data()), size());
+        return result;
+    }
+
+    void Serialize(std::ostream* out) const;
+    void Deserialize(std::istream* in);
+
+   private:
+    NullOr<const KeyParameter&> GetEntry(Tag tag) const;
+
+    std::vector<KeyParameter> data_;
+};
+
+class AuthorizationSetBuilder : public AuthorizationSet {
+   public:
+    template <typename TagType, typename... ValueType>
+    AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) {
+        push_back(ttag, std::forward<ValueType>(value)...);
+        return *this;
+    }
+
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data,
+                                           size_t data_length) {
+        hidl_vec<uint8_t> new_blob;
+        new_blob.setToExternal(const_cast<uint8_t*>(data), data_length);
+        push_back(ttag, std::move(new_blob));
+        return *this;
+    }
+
+    template <Tag tag>
+    AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const char* data,
+                                           size_t data_length) {
+        return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length);
+    }
+
+    AuthorizationSetBuilder& Authorizations(const AuthorizationSet& set) {
+        for (const auto& entry : set) {
+            push_back(entry);
+        }
+        return *this;
+    }
+
+    AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
+    AuthorizationSetBuilder& EcdsaKey(EcCurve curve);
+    AuthorizationSetBuilder& AesKey(uint32_t key_size);
+    AuthorizationSetBuilder& TripleDesKey(uint32_t key_size);
+    AuthorizationSetBuilder& HmacKey(uint32_t key_size);
+
+    AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent);
+    AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
+    AuthorizationSetBuilder& EcdsaSigningKey(EcCurve curve);
+    AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
+    AuthorizationSetBuilder& TripleDesEncryptionKey(uint32_t key_size);
+
+    AuthorizationSetBuilder& SigningKey();
+    AuthorizationSetBuilder& EncryptionKey();
+
+    AuthorizationSetBuilder& NoDigestOrPadding();
+
+    AuthorizationSetBuilder& EcbMode();
+    AuthorizationSetBuilder& GcmModeMinMacLen(uint32_t minMacLength);
+    AuthorizationSetBuilder& GcmModeMacLen(uint32_t macLength);
+
+    AuthorizationSetBuilder& BlockMode(std::initializer_list<BlockMode> blockModes);
+    AuthorizationSetBuilder& Digest(std::initializer_list<Digest> digests);
+    AuthorizationSetBuilder& Padding(std::initializer_list<PaddingMode> paddings);
+
+    template <typename... T>
+    AuthorizationSetBuilder& BlockMode(T&&... a) {
+        return BlockMode({std::forward<T>(a)...});
+    }
+    template <typename... T>
+    AuthorizationSetBuilder& Digest(T&&... a) {
+        return Digest({std::forward<T>(a)...});
+    }
+    template <typename... T>
+    AuthorizationSetBuilder& Padding(T&&... a) {
+        return Padding({std::forward<T>(a)...});
+    }
+};
+
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/key_param_output.h b/keymaster/4.0/support/include/keymasterV4_0/key_param_output.h
new file mode 100644
index 0000000..74be343
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/key_param_output.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+
+#include <android/hardware/keymaster/4.0/types.h>
+
+#include "keymaster_tags.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+inline ::std::ostream& operator<<(::std::ostream& os, Algorithm value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, BlockMode value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, Digest value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, EcCurve value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, ErrorCode value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, KeyOrigin value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, PaddingMode value) {
+    return os << toString(value);
+}
+
+template <typename ValueT>
+::std::ostream& operator<<(::std::ostream& os, const NullOr<ValueT>& value) {
+    if (!value.isOk()) {
+        os << "(value not present)";
+    } else {
+        os << value.value();
+    }
+    return os;
+}
+
+::std::ostream& operator<<(::std::ostream& os, const hidl_vec<KeyParameter>& set);
+::std::ostream& operator<<(::std::ostream& os, const KeyParameter& value);
+
+inline ::std::ostream& operator<<(::std::ostream& os, const KeyCharacteristics& value) {
+    return os << "SW: " << value.softwareEnforced << ::std::endl
+              << "HW: " << value.hardwareEnforced << ::std::endl;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, KeyPurpose value) {
+    return os << toString(value);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& os, Tag tag) {
+    return os << toString(tag);
+}
+
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
new file mode 100644
index 0000000..9d6501b
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -0,0 +1,428 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
+#define SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
+
+/**
+ * This header contains various definitions that make working with keymaster tags safer and easier.
+ *
+ * It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose
+ * of making it impossible to make certain classes of mistakes when operating on keymaster
+ * authorizations.  For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE
+ * and then to assign Algorithm::RSA to algorithm element of its union. But because the user
+ * must choose the union field, there could be a mismatch which the compiler has now way to
+ * diagnose.
+ *
+ * The machinery in this header solves these problems by describing which union field corresponds
+ * to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a
+ * numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG,
+ * we declare types for each of the tags defined in hardware/interfaces/keymaster/4.0/types.hal.
+ *
+ * The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance
+ * TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag
+ * to its value c++ type and the correct union element of KeyParameter. This is done by means of
+ * the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping
+ * a typed tag to the corresponding c++ type, and access function, accessTagValue returning a
+ * reference to the correct element of KeyParameter.
+ * E.g.:
+ *      given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)"
+ *      yields a reference to param.f.purpose
+ * If used in an assignment the compiler can now check the compatibility of the assigned value.
+ *
+ * For convenience we also provide the constructor like function Authorization().
+ * Authorization takes a typed tag and a value and checks at compile time whether the value given
+ * is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the
+ * given tag and value and returns it by value.
+ *
+ * The second convenience function, authorizationValue, allows access to the KeyParameter value in
+ * a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped
+ * by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped
+ * reference.
+ * E.g.:
+ *      auto param = Authorization(TAG_ALGORITM, Algorithm::RSA);
+ *      auto value1 = authorizationValue(TAG_PURPOSE, param);
+ *      auto value2 = authorizationValue(TAG_ALGORITM, param);
+ * value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access.
+ */
+
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+
+#include <type_traits>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have.  We
+// need these old values to be able to support old keys that use them.
+static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5;
+static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7;
+
+constexpr TagType typeFromTag(Tag tag) {
+    return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000));
+}
+
+/**
+ * TypedTag is a templatized version of Tag, which provides compile-time checking of
+ * keymaster tag types. Instances are convertible to Tag, so they can be used wherever
+ * Tag is expected, and because they encode the tag type it's possible to create
+ * function overloads that only operate on tags with a particular type.
+ */
+template <TagType tag_type, Tag tag>
+struct TypedTag {
+    inline TypedTag() {
+        // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type
+        // 'tag_type'.  Attempting to instantiate a tag with the wrong type will result in a compile
+        // error (no match for template specialization StaticAssert<false>), with no run-time cost.
+        static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type");
+    }
+    operator Tag() const { return tag; }
+    int32_t maskedTag() { return tag & 0x0FFFFFFF; }
+};
+
+template <Tag tag>
+struct Tag2TypedTag {
+    typedef TypedTag<typeFromTag(tag), tag> type;
+};
+
+#define DECLARE_TYPED_TAG(name)                                    \
+    typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \
+    static TAG_##name##_t TAG_##name;
+
+DECLARE_TYPED_TAG(ACTIVE_DATETIME);
+DECLARE_TYPED_TAG(ALGORITHM);
+DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY);
+DECLARE_TYPED_TAG(APPLICATION_DATA);
+DECLARE_TYPED_TAG(APPLICATION_ID);
+DECLARE_TYPED_TAG(ASSOCIATED_DATA);
+DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID);
+DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE);
+DECLARE_TYPED_TAG(AUTH_TIMEOUT);
+DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS);
+DECLARE_TYPED_TAG(BLOCK_MODE);
+DECLARE_TYPED_TAG(BOOTLOADER_ONLY);
+DECLARE_TYPED_TAG(CALLER_NONCE);
+DECLARE_TYPED_TAG(CONFIRMATION_TOKEN);
+DECLARE_TYPED_TAG(CREATION_DATETIME);
+DECLARE_TYPED_TAG(DIGEST);
+DECLARE_TYPED_TAG(EC_CURVE);
+DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID);
+DECLARE_TYPED_TAG(INVALID);
+DECLARE_TYPED_TAG(KEY_SIZE);
+DECLARE_TYPED_TAG(MAC_LENGTH);
+DECLARE_TYPED_TAG(MAX_USES_PER_BOOT);
+DECLARE_TYPED_TAG(MIN_MAC_LENGTH);
+DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS);
+DECLARE_TYPED_TAG(NONCE);
+DECLARE_TYPED_TAG(NO_AUTH_REQUIRED);
+DECLARE_TYPED_TAG(ORIGIN);
+DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(OS_PATCHLEVEL);
+DECLARE_TYPED_TAG(OS_VERSION);
+DECLARE_TYPED_TAG(PADDING);
+DECLARE_TYPED_TAG(PURPOSE);
+DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION);
+DECLARE_TYPED_TAG(ROLLBACK_RESISTANCE);
+DECLARE_TYPED_TAG(ROOT_OF_TRUST);
+DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT);
+DECLARE_TYPED_TAG(TRUSTED_CONFIRMATION_REQUIRED);
+DECLARE_TYPED_TAG(UNIQUE_ID);
+DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME);
+DECLARE_TYPED_TAG(USER_AUTH_TYPE);
+DECLARE_TYPED_TAG(USER_SECURE_ID);
+
+template <typename... Elems>
+struct MetaList {};
+
+using all_tags_t = MetaList<
+    TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t,
+    TAG_RSA_PUBLIC_EXPONENT_t, TAG_INCLUDE_UNIQUE_ID_t, TAG_ACTIVE_DATETIME_t,
+    TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, TAG_MIN_SECONDS_BETWEEN_OPS_t,
+    TAG_MAX_USES_PER_BOOT_t, TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t,
+    TAG_ALLOW_WHILE_ON_BODY_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t,
+    TAG_CREATION_DATETIME_t, TAG_ROLLBACK_RESISTANCE_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t,
+    TAG_NONCE_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t,
+    TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t,
+    TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t,
+    TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_EC_CURVE_t>;
+
+template <typename TypedTagType>
+struct TypedTag2ValueType;
+
+#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name)                              \
+    template <Tag tag>                                                             \
+    struct TypedTag2ValueType<TypedTag<tag_type, tag>> {                           \
+        typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type;    \
+    };                                                                             \
+    template <Tag tag>                                                             \
+    inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) \
+        ->const decltype(param.field_name)& {                                      \
+        return param.field_name;                                                   \
+    }                                                                              \
+    template <Tag tag>                                                             \
+    inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param)       \
+        ->decltype(param.field_name)& {                                            \
+        return param.field_name;                                                   \
+    }
+
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger)
+MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob)
+MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob)
+
+#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name)                     \
+    template <>                                                                 \
+    struct TypedTag2ValueType<decltype(typed_tag)> {                            \
+        typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \
+    };                                                                          \
+    inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param)  \
+        ->const decltype(param.field_name)& {                                   \
+        return param.field_name;                                                \
+    }                                                                           \
+    inline auto accessTagValue(decltype(typed_tag), KeyParameter& param)        \
+        ->decltype(param.field_name)& {                                         \
+        return param.field_name;                                                \
+    }
+
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose)
+MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType)
+
+template <TagType tag_type, Tag tag, typename ValueT>
+inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) {
+    KeyParameter param;
+    param.tag = tag;
+    param.f.longInteger = 0;
+    accessTagValue(ttag, param) = std::forward<ValueT>(value);
+    return param;
+}
+
+// the boolean case
+template <Tag tag>
+inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) {
+    KeyParameter param;
+    param.tag = tag;
+    param.f.boolValue = true;
+    return param;
+}
+
+template <typename... Pack>
+struct FirstOrNoneHelper;
+template <typename First>
+struct FirstOrNoneHelper<First> {
+    typedef First type;
+};
+template <>
+struct FirstOrNoneHelper<> {
+    struct type {};
+};
+
+template <typename... Pack>
+using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type;
+
+template <TagType tag_type, Tag tag, typename... Args>
+inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) {
+    static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0),
+                  "TagType::BOOL Authorizations do not take parameters. Presence is truth.");
+    static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1),
+                  "Authorization other then TagType::BOOL take exactly one parameter.");
+    static_assert(
+        tag_type == TagType::BOOL ||
+            std::is_convertible<std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>,
+                                typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value,
+        "Invalid argument type for given tag.");
+
+    return makeKeyParameter(ttag, std::forward<Args>(args)...);
+}
+
+/**
+ * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out
+ * of band. Note that if the wrapped value is a reference it is unsafe to access the value if
+ * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the
+ * wrapped value. In this case the pointer will be NULL though, and the value will be default
+ * constructed.
+ */
+template <typename ValueT>
+class NullOr {
+    template <typename T>
+    struct reference_initializer {
+        static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
+    };
+    template <typename T>
+    struct pointer_initializer {
+        static T init() { return nullptr; }
+    };
+    template <typename T>
+    struct value_initializer {
+        static T init() { return T(); }
+    };
+    template <typename T>
+    using initializer_t =
+        std::conditional_t<std::is_lvalue_reference<T>::value, reference_initializer<T>,
+                           std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>,
+                                              value_initializer<T>>>;
+
+   public:
+    NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
+    NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}
+
+    bool isOk() const { return !null_; }
+
+    const ValueT& value() const & { return value_; }
+    ValueT& value() & { return value_; }
+    ValueT&& value() && { return std::move(value_); }
+
+   private:
+    ValueT value_;
+    bool null_;
+};
+
+template <typename T>
+std::remove_reference_t<T> NullOrOr(T&& v) {
+    if (v.isOk()) return v;
+    return {};
+}
+
+template <typename Head, typename... Tail>
+std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) {
+    if (head.isOk()) return head;
+    return NullOrOr(std::forward<Tail>(tail)...);
+}
+
+template <typename Default, typename Wrapped>
+std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) {
+    static_assert(std::is_convertible<std::remove_reference_t<Default>,
+                                      std::remove_reference_t<Wrapped>>::value,
+                  "Type of default value must match the type wrapped by NullOr");
+    if (optional.isOk()) return optional.value();
+    return def;
+}
+
+template <TagType tag_type, Tag tag>
+inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> authorizationValue(
+    TypedTag<tag_type, tag> ttag, const KeyParameter& param) {
+    if (tag != param.tag) return {};
+    return accessTagValue(ttag, param);
+}
+
+inline bool operator==(const KeyParameter& a, const KeyParameter& b) {
+    if (a.tag != b.tag) {
+        return false;
+    }
+
+    switch (a.tag) {
+        /* Boolean tags */
+        case Tag::INVALID:
+        case Tag::CALLER_NONCE:
+        case Tag::INCLUDE_UNIQUE_ID:
+        case Tag::BOOTLOADER_ONLY:
+        case Tag::NO_AUTH_REQUIRED:
+        case Tag::ALLOW_WHILE_ON_BODY:
+        case Tag::ROLLBACK_RESISTANCE:
+        case Tag::RESET_SINCE_ID_ROTATION:
+        case Tag::TRUSTED_CONFIRMATION_REQUIRED:
+        case Tag::TRUSTED_USER_PRESENCE_REQUIRED:
+            return true;
+
+        /* Integer tags */
+        case Tag::KEY_SIZE:
+        case Tag::MIN_MAC_LENGTH:
+        case Tag::MIN_SECONDS_BETWEEN_OPS:
+        case Tag::MAX_USES_PER_BOOT:
+        case Tag::OS_VERSION:
+        case Tag::OS_PATCHLEVEL:
+        case Tag::MAC_LENGTH:
+        case Tag::AUTH_TIMEOUT:
+        case Tag::VENDOR_PATCHLEVEL:
+        case Tag::BOOT_PATCHLEVEL:
+            return a.f.integer == b.f.integer;
+
+        /* Long integer tags */
+        case Tag::RSA_PUBLIC_EXPONENT:
+        case Tag::USER_SECURE_ID:
+            return a.f.longInteger == b.f.longInteger;
+
+        /* Date-time tags */
+        case Tag::ACTIVE_DATETIME:
+        case Tag::ORIGINATION_EXPIRE_DATETIME:
+        case Tag::USAGE_EXPIRE_DATETIME:
+        case Tag::CREATION_DATETIME:
+            return a.f.dateTime == b.f.dateTime;
+
+        /* Bytes tags */
+        case Tag::APPLICATION_ID:
+        case Tag::APPLICATION_DATA:
+        case Tag::ROOT_OF_TRUST:
+        case Tag::UNIQUE_ID:
+        case Tag::ATTESTATION_CHALLENGE:
+        case Tag::ATTESTATION_APPLICATION_ID:
+        case Tag::ATTESTATION_ID_BRAND:
+        case Tag::ATTESTATION_ID_DEVICE:
+        case Tag::ATTESTATION_ID_PRODUCT:
+        case Tag::ATTESTATION_ID_SERIAL:
+        case Tag::ATTESTATION_ID_IMEI:
+        case Tag::ATTESTATION_ID_MEID:
+        case Tag::ATTESTATION_ID_MANUFACTURER:
+        case Tag::ATTESTATION_ID_MODEL:
+        case Tag::ASSOCIATED_DATA:
+        case Tag::CONFIRMATION_TOKEN:
+        case Tag::NONCE:
+            return a.blob == b.blob;
+
+        /* Enum tags */
+        case Tag::PURPOSE:
+            return a.f.purpose == b.f.purpose;
+        case Tag::ALGORITHM:
+            return a.f.algorithm == b.f.algorithm;
+        case Tag::BLOCK_MODE:
+            return a.f.blockMode == b.f.blockMode;
+        case Tag::DIGEST:
+            return a.f.digest == b.f.digest;
+        case Tag::PADDING:
+            return a.f.paddingMode == b.f.paddingMode;
+        case Tag::EC_CURVE:
+            return a.f.ecCurve == b.f.ecCurve;
+        case Tag::BLOB_USAGE_REQUIREMENTS:
+            return a.f.keyBlobUsageRequirements == b.f.keyBlobUsageRequirements;
+        case Tag::USER_AUTH_TYPE:
+            return a.f.integer == b.f.integer;
+        case Tag::ORIGIN:
+            return a.f.origin == b.f.origin;
+        case Tag::HARDWARE_TYPE:
+            return a.f.hardwareType == b.f.hardwareType;
+    }
+
+    return false;
+}
+
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
new file mode 100644
index 0000000..1c1b000
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_utils.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
+
+#include <android/hardware/keymaster/4.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length,
+                                             bool inPlace = true) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<unsigned char*>(data), length, !inPlace);
+    return result;
+}
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::string& value, bool inPlace = true) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(value.data())),
+                         static_cast<size_t>(value.size()), !inPlace);
+    return result;
+}
+
+inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob,
+                                             bool inPlace = true) {
+    hidl_vec<uint8_t> result;
+    result.setToExternal(const_cast<uint8_t*>(blob.data()), static_cast<size_t>(blob.size()),
+                         !inPlace);
+    return result;
+}
+
+HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer);
+hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token);
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_UTILS_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
new file mode 100644
index 0000000..cc71dd1
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/openssl_utils.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_
+#define HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_
+
+#include <android/hardware/keymaster/4.0/types.h>
+
+template <typename T, void (*F)(T*)>
+struct UniquePtrDeleter {
+    void operator()(T* p) const { F(p); }
+};
+
+typedef UniquePtrDeleter<EVP_PKEY, EVP_PKEY_free> EVP_PKEY_Delete;
+
+#define MAKE_OPENSSL_PTR_TYPE(type) \
+    typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr;
+
+MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT)
+MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
+MAKE_OPENSSL_PTR_TYPE(RSA)
+MAKE_OPENSSL_PTR_TYPE(X509)
+MAKE_OPENSSL_PTR_TYPE(BN_CTX)
+
+typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr;
+
+inline const EVP_MD* openssl_digest(android::hardware::keymaster::V4_0::Digest digest) {
+    switch (digest) {
+        case android::hardware::keymaster::V4_0::Digest::NONE:
+            return nullptr;
+        case android::hardware::keymaster::V4_0::Digest::MD5:
+            return EVP_md5();
+        case android::hardware::keymaster::V4_0::Digest::SHA1:
+            return EVP_sha1();
+        case android::hardware::keymaster::V4_0::Digest::SHA_2_224:
+            return EVP_sha224();
+        case android::hardware::keymaster::V4_0::Digest::SHA_2_256:
+            return EVP_sha256();
+        case android::hardware::keymaster::V4_0::Digest::SHA_2_384:
+            return EVP_sha384();
+        case android::hardware::keymaster::V4_0::Digest::SHA_2_512:
+            return EVP_sha512();
+    }
+    return nullptr;
+}
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_4_0_SUPPORT_OPENSSL_UTILS_H_
diff --git a/keymaster/4.0/support/key_param_output.cpp b/keymaster/4.0/support/key_param_output.cpp
new file mode 100644
index 0000000..e90e2fe
--- /dev/null
+++ b/keymaster/4.0/support/key_param_output.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keymasterV4_0/key_param_output.h>
+
+#include <keymasterV4_0/keymaster_tags.h>
+
+#include <iomanip>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+
+using ::std::ostream;
+using ::std::endl;
+
+namespace V4_0 {
+
+ostream& operator<<(ostream& os, const hidl_vec<KeyParameter>& set) {
+    if (set.size() == 0) {
+        os << "(Empty)" << endl;
+    } else {
+        os << "\n";
+        for (const auto& elem : set) os << elem << endl;
+    }
+    return os;
+}
+
+ostream& operator<<(ostream& os, const KeyParameter& param) {
+    os << param.tag << ": ";
+    switch (typeFromTag(param.tag)) {
+        case TagType::INVALID:
+            return os << " Invalid";
+        case TagType::UINT_REP:
+        case TagType::UINT:
+            return os << param.f.integer;
+        case TagType::ENUM_REP:
+        case TagType::ENUM:
+            switch (param.tag) {
+                case Tag::ALGORITHM:
+                    return os << param.f.algorithm;
+                case Tag::BLOCK_MODE:
+                    return os << param.f.blockMode;
+                case Tag::PADDING:
+                    return os << param.f.paddingMode;
+                case Tag::DIGEST:
+                    return os << param.f.digest;
+                case Tag::EC_CURVE:
+                    return os << (int)param.f.ecCurve;
+                case Tag::ORIGIN:
+                    return os << param.f.origin;
+                case Tag::BLOB_USAGE_REQUIREMENTS:
+                    return os << (int)param.f.keyBlobUsageRequirements;
+                case Tag::PURPOSE:
+                    return os << param.f.purpose;
+                default:
+                    return os << " UNKNOWN ENUM " << param.f.integer;
+            }
+        case TagType::ULONG_REP:
+        case TagType::ULONG:
+            return os << param.f.longInteger;
+        case TagType::DATE:
+            return os << param.f.dateTime;
+        case TagType::BOOL:
+            return os << "true";
+        case TagType::BIGNUM:
+            os << " Bignum: ";
+            for (size_t i = 0; i < param.blob.size(); ++i) {
+                os << std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec;
+            }
+            return os;
+        case TagType::BYTES:
+            os << " Bytes: ";
+            for (size_t i = 0; i < param.blob.size(); ++i) {
+                os << ::std::hex << ::std::setw(2) << static_cast<int>(param.blob[i]) << ::std::dec;
+            }
+            return os;
+    }
+    return os << "UNKNOWN TAG TYPE!";
+}
+
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/support/keymaster_utils.cpp b/keymaster/4.0/support/keymaster_utils.cpp
new file mode 100644
index 0000000..bc610aa
--- /dev/null
+++ b/keymaster/4.0/support/keymaster_utils.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware/hw_auth_token.h>
+#include <keymasterV4_0/keymaster_utils.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+template <typename T, typename InIter>
+inline static InIter copy_bytes_from_iterator(T* value, InIter src) {
+    uint8_t* value_ptr = reinterpret_cast<uint8_t*>(value);
+    std::copy(src, src + sizeof(T), value_ptr);
+    return src + sizeof(T);
+}
+
+template <typename T, typename OutIter>
+inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
+    const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
+    return std::copy(value_ptr, value_ptr + sizeof(value), dest);
+}
+
+constexpr size_t kHmacSize = 32;
+
+hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) {
+    static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
+                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+                          sizeof(token.timestamp) + kHmacSize ==
+                      sizeof(hw_auth_token_t),
+                  "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+    hidl_vec<uint8_t> result;
+    result.resize(sizeof(hw_auth_token_t));
+    auto pos = result.begin();
+    *pos++ = 0;  // Version byte
+    pos = copy_bytes_to_iterator(token.challenge, pos);
+    pos = copy_bytes_to_iterator(token.userId, pos);
+    pos = copy_bytes_to_iterator(token.authenticatorId, pos);
+    auto auth_type = htonl(static_cast<uint32_t>(token.authenticatorType));
+    pos = copy_bytes_to_iterator(auth_type, pos);
+    auto timestamp = htonq(token.timestamp);
+    pos = copy_bytes_to_iterator(timestamp, pos);
+    if (token.mac.size() != kHmacSize) {
+        std::fill(pos, pos + kHmacSize, 0);
+    } else {
+        std::copy(token.mac.begin(), token.mac.end(), pos);
+    }
+
+    return result;
+}
+
+HardwareAuthToken hidlVec2AuthToken(const hidl_vec<uint8_t>& buffer) {
+    HardwareAuthToken token;
+    static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
+                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+                          sizeof(token.timestamp) + kHmacSize ==
+                      sizeof(hw_auth_token_t),
+                  "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+    if (buffer.size() != sizeof(hw_auth_token_t)) return {};
+
+    auto pos = buffer.begin();
+    ++pos;  // skip first byte
+    pos = copy_bytes_from_iterator(&token.challenge, pos);
+    pos = copy_bytes_from_iterator(&token.userId, pos);
+    pos = copy_bytes_from_iterator(&token.authenticatorId, pos);
+    pos = copy_bytes_from_iterator(&token.authenticatorType, pos);
+    token.authenticatorType = static_cast<HardwareAuthenticatorType>(
+        ntohl(static_cast<uint32_t>(token.authenticatorType)));
+    pos = copy_bytes_from_iterator(&token.timestamp, pos);
+    token.timestamp = ntohq(token.timestamp);
+    token.mac.resize(kHmacSize);
+    std::copy(pos, pos + kHmacSize, token.mac.data());
+
+    return token;
+}
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/types.hal b/keymaster/4.0/types.hal
new file mode 100644
index 0000000..91ec9bf
--- /dev/null
+++ b/keymaster/4.0/types.hal
@@ -0,0 +1,704 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.keymaster@4.0;
+
+/**
+ * Time in milliseconds since some arbitrary point in time.  Time must be monotonically increasing,
+ * and a secure environment's notion of "current time" must not repeat until the Android device
+ * reboots, or until at least 50 million years have elapsed (note that this requirement is satisfied
+ * by setting the clock to zero during each boot, and then counting time accurately).
+ */
+typedef uint64_t Timestamp;
+
+/**
+ * A place to define any needed constants.
+ */
+enum Constants : uint32_t {
+    AUTH_TOKEN_MAC_LENGTH = 32,
+};
+
+enum TagType : uint32_t {
+    /** Invalid type, used to designate a tag as uninitialized. */
+    INVALID = 0 << 28,
+    /** Enumeration value. */
+    ENUM = 1 << 28,
+    /** Repeatable enumeration value. */
+    ENUM_REP = 2 << 28,
+    /** 32-bit unsigned integer. */
+    UINT = 3 << 28,
+    /** Repeatable 32-bit unsigned integer. */
+    UINT_REP = 4 << 28,
+    /** 64-bit unsigned integer. */
+    ULONG = 5 << 28,
+    /** 64-bit unsigned integer representing a date and time, in milliseconds since 1 Jan 1970. */
+    DATE = 6 << 28,
+    /** Boolean.  If a tag with this type is present, the value is "true".  If absent, "false". */
+    BOOL = 7 << 28,
+    /** Byte string containing an arbitrary-length integer, big-endian ordering. */
+    BIGNUM = 8 << 28,
+    /** Byte string */
+    BYTES = 9 << 28,
+    /** Repeatable 64-bit unsigned integer */
+    ULONG_REP = 10 << 28,
+};
+
+enum Tag : uint32_t {
+    INVALID = TagType:INVALID | 0,
+
+    /*
+     * Tags that must be semantically enforced by hardware and software implementations.
+     */
+
+    /* Crypto parameters */
+    PURPOSE = TagType:ENUM_REP | 1,    /* KeyPurpose. */
+    ALGORITHM = TagType:ENUM | 2,      /* Algorithm. */
+    KEY_SIZE = TagType:UINT | 3,       /* Key size in bits. */
+    BLOCK_MODE = TagType:ENUM_REP | 4, /* BlockMode. */
+    DIGEST = TagType:ENUM_REP | 5,     /* Digest. */
+    PADDING = TagType:ENUM_REP | 6,    /* PaddingMode. */
+    CALLER_NONCE = TagType:BOOL | 7,   /* Allow caller to specify nonce or IV. */
+    MIN_MAC_LENGTH = TagType:UINT | 8, /* Minimum length of MAC or AEAD authentication tag in
+                                        * bits. */
+    // 9 reserved
+    EC_CURVE = TagType:ENUM | 10,      /* EcCurve. */
+
+    /* Algorithm-specific. */
+    RSA_PUBLIC_EXPONENT = TagType:ULONG | 200,
+    // 201 reserved for ECIES
+    INCLUDE_UNIQUE_ID = TagType:BOOL | 202, /* If true, attestation certificates for this key must
+                                             * contain an application-scoped and time-bounded
+                                             * device-unique ID.*/
+
+    /* Other hardware-enforced. */
+    BLOB_USAGE_REQUIREMENTS = TagType:ENUM | 301, /* KeyBlobUsageRequirements. */
+    BOOTLOADER_ONLY = TagType:BOOL | 302,         /* Usable only by bootloader. */
+    ROLLBACK_RESISTANCE = TagType:BOOL | 303,     /* Whether key is rollback-resistant.  Specified
+                                                   * in the key description provided to generateKey
+                                                   * or importKey if rollback resistance is desired.
+                                                   * If the implementation cannot provide rollback
+                                                   * resistance, it must return
+                                                   * ROLLBACK_RESISTANCE_UNAVAILABLE. */
+
+    /* HARDWARE_TYPE specifies the type of the secure hardware that is requested for the key
+     * generation / import.  See the SecurityLevel enum.  In the absence of this tag, keystore must
+     * use TRUSTED_ENVIRONMENT.  If this tag is present and the requested hardware type is not
+     * available, Keymaster returns HARDWARE_TYPE_UNAVAILABLE. This tag is not included in
+     * attestations, but hardware type must be reflected in the Keymaster SecurityLevel of the
+     * attestation header. */
+    HARDWARE_TYPE = TagType:ENUM | 304,
+
+    /*
+     * Tags that should be semantically enforced by hardware if possible and will otherwise be
+     * enforced by software (keystore).
+     */
+
+    /* Key validity period */
+    ACTIVE_DATETIME = TagType:DATE | 400,             /* Start of validity. */
+    ORIGINATION_EXPIRE_DATETIME = TagType:DATE | 401, /* Date when new "messages" should no longer
+                                                       * be created. */
+    USAGE_EXPIRE_DATETIME = TagType:DATE | 402,       /* Date when existing "messages" should no
+                                                       * longer be trusted. */
+    MIN_SECONDS_BETWEEN_OPS = TagType:UINT | 403,     /* Minimum elapsed time between
+                                                       * cryptographic operations with the key. */
+    MAX_USES_PER_BOOT = TagType:UINT | 404,           /* Number of times the key can be used per
+                                                       * boot. */
+
+    /* User authentication */
+    // 500-501 reserved
+    USER_SECURE_ID = TagType:ULONG_REP | 502, /* Secure ID of authorized user or authenticator(s).
+                                               * Disallowed if NO_AUTH_REQUIRED is present. */
+    NO_AUTH_REQUIRED = TagType:BOOL | 503,    /* If key is usable without authentication. */
+    USER_AUTH_TYPE = TagType:ENUM | 504,      /* Bitmask of authenticator types allowed when
+                                               * USER_SECURE_ID contains a secure user ID, rather
+                                               * than a secure authenticator ID.  Defined in
+                                               * HardwareAuthenticatorType. */
+    AUTH_TIMEOUT = TagType:UINT | 505,        /* Required freshness of user authentication for
+                                               * private/secret key operations, in seconds.  Public
+                                               * key operations require no authentication.  If
+                                               * absent, authentication is required for every use.
+                                               * Authentication state is lost when the device is
+                                               * powered off. */
+    ALLOW_WHILE_ON_BODY =  TagType:BOOL | 506, /* Allow key to be used after authentication timeout
+                                                * if device is still on-body (requires secure
+                                                * on-body sensor. */
+
+    /**
+     * TRUSTED_USER_PRESENCE_REQUIRED is an optional feature that specifies that this key must be
+     * unusable except when the user has provided proof of physical presence.  Proof of physical
+     * presence must be a signal that cannot be triggered by an attacker who doesn't have one of:
+     *
+     *    a) Physical control of the device or
+     *
+     *    b) Control of the secure environment that holds the key.
+     *
+     * For instance, proof of user identity may be considered proof of presence if it meets the
+     * requirements.  However, proof of identity established in one security domain (e.g. TEE) does
+     * not constitute proof of presence in another security domain (e.g. StrongBox), and no
+     * mechanism analogous to the authentication token is defined for communicating proof of
+     * presence across security domains.
+     *
+     * Some examples:
+     *
+     *     A hardware button hardwired to a pin on a StrongBox device in such a way that nothing
+     *     other than a button press can trigger the signal constitutes proof of physical presence
+     *     for StrongBox keys.
+     *
+     *     Fingerprint authentication provides proof of presence (and identity) for TEE keys if the
+     *     TEE has exclusive control of the fingerprint scanner and performs fingerprint matching.
+     *
+     *     Password authentication does not provide proof of presence to either TEE or StrongBox,
+     *     even if TEE or StrongBox does the password matching, because password input is handled by
+     *     the non-secure world, which means an attacker who has compromised Android can spoof
+     *     password authentication.
+     *
+     * Note that no mechanism is defined for delivering proof of presence to Keymaster,
+     * except perhaps as implied by an auth token.  This means that Keymaster must be able to check
+     * proof of presence some other way.  Further, the proof of presence must be performed between
+     * begin() and the first call to update() or finish().  If the first update() or the finish()
+     * call is made without proof of presence, the keymaster method must return
+     * ErrorCode::PROOF_OF_PRESENCE_REQUIRED and abort the operation.  The caller must delay the
+     * update() or finish() call until proof of presence has been provided, which means the caller
+     * must also have some mechanism for verifying that the proof has been provided.
+     *
+     * Only one operation requiring TUP may be in flight at a time.  If begin() has already been
+     * called on one key with TRUSTED_USER_PRESENCE_REQUIRED, and another begin() comes in for that
+     * key or another with TRUSTED_USER_PRESENCE_REQUIRED, Keymaster must return
+     * ErrorCode::CONCURRENT_PROOF_OF_PRESENCE_REQUESTED.
+     */
+    TRUSTED_USER_PRESENCE_REQUIRED = TagType:BOOL | 507,
+
+    /** TRUSTED_CONFIRMATION_REQUIRED is only applicable to keys with KeyPurpose SIGN, and specifies
+     *  that this key must not be usable unless the user provides confirmation of the data to be
+     *  signed. Confirmation is proven to keymaster via an approval token. See CONFIRMATION_TOKEN,
+     *  as well as the ConfirmatinUI HAL.
+     *
+     * If an attempt to use a key with this tag does not have a cryptographically valid
+     * CONFIRMATION_TOKEN provided to finish() or if the data provided to update()/finish() does not
+     * match the data described in the token, keymaster must return NO_USER_CONFIRMATION. */
+    TRUSTED_CONFIRMATION_REQUIRED = TagType:BOOL | 508,
+
+    /* Application access control */
+    APPLICATION_ID = TagType:BYTES | 601, /* Byte string identifying the authorized application. */
+
+    /*
+     * Semantically unenforceable tags, either because they have no specific meaning or because
+     * they're informational only.
+     */
+    APPLICATION_DATA = TagType:BYTES | 700, /* Data provided by authorized application. */
+    CREATION_DATETIME = TagType:DATE | 701, /* Key creation time */
+    ORIGIN = TagType:ENUM | 702,            /* keymaster_key_origin_t. */
+    // 703 is unused.
+    ROOT_OF_TRUST = TagType:BYTES | 704,         /* Root of trust ID. */
+    OS_VERSION = TagType:UINT | 705,             /* Version of system (keymaster2) */
+    OS_PATCHLEVEL = TagType:UINT | 706,          /* Patch level of system (keymaster2) */
+    UNIQUE_ID = TagType:BYTES | 707,             /* Used to provide unique ID in attestation */
+    ATTESTATION_CHALLENGE = TagType:BYTES | 708, /* Used to provide challenge in attestation */
+    ATTESTATION_APPLICATION_ID = TagType:BYTES | 709, /* Used to identify the set of possible
+                                                       * applications of which one has initiated a
+                                                       * key attestation */
+    ATTESTATION_ID_BRAND = TagType:BYTES | 710,   /* Used to provide the device's brand name to be
+                                                   * included in attestation */
+    ATTESTATION_ID_DEVICE = TagType:BYTES | 711,  /* Used to provide the device's device name to
+                                                   * be included in attestation */
+    ATTESTATION_ID_PRODUCT = TagType:BYTES | 712, /* Used to provide the device's product name to
+                                                   * be included in attestation */
+    ATTESTATION_ID_SERIAL =
+    TagType:BYTES | 713,                       /* Used to provide the device's serial number to be
+                                                * included in attestation */
+    ATTESTATION_ID_IMEI = TagType:BYTES | 714, /* Used to provide the device's IMEI to be included
+                                                * in attestation */
+    ATTESTATION_ID_MEID = TagType:BYTES | 715, /* Used to provide the device's MEID to be included
+                                                * in attestation */
+    ATTESTATION_ID_MANUFACTURER =
+    TagType:BYTES | 716,                        /* Used to provide the device's manufacturer
+                                                 * name to be included in attestation */
+    ATTESTATION_ID_MODEL = TagType:BYTES | 717, /* Used to provide the device's model name to be
+                                                 * included in attestation */
+
+    /**
+     * Patch level of vendor image.  The value is an integer of the form YYYYMM, where YYYY is the
+     * four-digit year when the vendor image was released and MM is the two-digit month.  During
+     * each boot, the bootloader must provide the patch level of the vendor image to keymaser
+     * (mechanism is implemntation-defined).  When keymaster keys are created or updated, the
+     * VENDOR_PATCHLEVEL tag must be cryptographically bound to the keys, with the current value as
+     * provided by the bootloader.  When keys are used, keymaster must verify that the
+     * VENDOR_PATCHLEVEL bound to the key matches the current value.  If they do not match,
+     * keymaster must return ErrorCode::KEY_REQUIRES_UPGRADE.  The client must then call upgradeKey.
+     */
+    VENDOR_PATCHLEVEL = TagType:UINT | 718,
+
+    /**
+     * Patch level of boot image.  The value is an integer of the form YYYYMM, where YYYY is the
+     * four-digit year when the boot image was released and MM is the two-digit month.  During each
+     * boot, the bootloader must provide the patch level of the boot image to keymaser (mechanism is
+     * implemntation-defined).  When keymaster keys are created or updated, the BOOT_PATCHLEVEL tag
+     * must be cryptographically bound to the keys, with the current value as provided by the
+     * bootloader.  When keys are used, keymaster must verify that the BOOT_PATCHLEVEL bound to the
+     * key matches the current value.  If they do not match, keymaster must return
+     * ErrorCode::KEY_REQUIRES_UPGRADE.  The client must then call upgradeKey.
+     */
+    BOOT_PATCHLEVEL = TagType:UINT | 719,
+
+    /* Tags used only to provide data to or receive data from operations */
+    ASSOCIATED_DATA = TagType:BYTES | 1000, /* Used to provide associated data for AEAD modes. */
+    NONCE = TagType:BYTES | 1001,           /* Nonce or Initialization Vector */
+    MAC_LENGTH = TagType:UINT | 1003,       /* MAC or AEAD authentication tag length in bits. */
+
+    RESET_SINCE_ID_ROTATION = TagType:BOOL | 1004, /* Whether the device has beeen factory reset
+                                                    * since the last unique ID rotation.  Used for
+                                                    * key attestation. */
+
+    /**
+     * CONFIRMATION_TOKEN is used to deliver a cryptographic token proving that the user confirmed a
+     * signing request. The content is a full-length HMAC-SHA256 value. See the ConfirmationUI HAL
+     * for details of token computation.
+     */
+    CONFIRMATION_TOKEN = TagType:BYTES | 1005,
+};
+
+/**
+ * Algorithms provided by keymaser implementations.
+ */
+enum Algorithm : uint32_t {
+    /** Asymmetric algorithms. */
+    RSA = 1,
+    // DSA = 2, -- Removed, do not re-use value 2.
+    EC = 3,
+
+    /** Block ciphers algorithms */
+    AES = 32,
+    TRIPLE_DES = 33,
+
+    /** MAC algorithms */
+    HMAC = 128,
+};
+
+/**
+ * Symmetric block cipher modes provided by keymaster implementations.
+ */
+enum BlockMode : uint32_t {
+    /*
+     * Unauthenticated modes, usable only for encryption/decryption and not generally recommended
+     * except for compatibility with existing other protocols.
+     */
+    ECB = 1,
+    CBC = 2,
+    CTR = 3,
+
+    /*
+     * Authenticated modes, usable for encryption/decryption and signing/verification.  Recommended
+     * over unauthenticated modes for all purposes.
+     */
+    GCM = 32,
+};
+
+/**
+ * Padding modes that may be applied to plaintext for encryption operations.  This list includes
+ * padding modes for both symmetric and asymmetric algorithms.  Note that implementations should not
+ * provide all possible combinations of algorithm and padding, only the
+ * cryptographically-appropriate pairs.
+ */
+enum PaddingMode : uint32_t {
+    NONE = 1, /* deprecated */
+    RSA_OAEP = 2,
+    RSA_PSS = 3,
+    RSA_PKCS1_1_5_ENCRYPT = 4,
+    RSA_PKCS1_1_5_SIGN = 5,
+    PKCS7 = 64,
+};
+
+/**
+ * Digests provided by keymaster implementations.
+ */
+enum Digest : uint32_t {
+    NONE = 0,
+    MD5 = 1,
+    SHA1 = 2,
+    SHA_2_224 = 3,
+    SHA_2_256 = 4,
+    SHA_2_384 = 5,
+    SHA_2_512 = 6,
+};
+
+/**
+ * Supported EC curves, used in ECDSA
+ */
+enum EcCurve : uint32_t {
+    P_224 = 0,
+    P_256 = 1,
+    P_384 = 2,
+    P_521 = 3,
+};
+
+/**
+ * The origin of a key (or pair), i.e. where it was generated.  Note that ORIGIN can be found in
+ * either the hardware-enforced or software-enforced list for a key, indicating whether the key is
+ * hardware or software-based.  Specifically, a key with GENERATED in the hardware-enforced list
+ * must be guaranteed never to have existed outide the secure hardware.
+ */
+enum KeyOrigin : uint32_t {
+    /** Generated in keymaster.  Should not exist outside the TEE. */
+    GENERATED = 0,
+
+    /** Derived inside keymaster.  Likely exists off-device. */
+    DERIVED = 1,
+
+    /** Imported into keymaster.  Existed as cleartext in Android. */
+    IMPORTED = 2,
+
+    /**
+     * Keymaster did not record origin.  This value can only be seen on keys in a keymaster0
+     * implementation.  The keymaster0 adapter uses this value to document the fact that it is
+     * unkown whether the key was generated inside or imported into keymaster.
+     */
+    UNKNOWN = 3,
+
+    /**
+     * Securely imported into Keymaster.  Was created elsewhere, and passed securely through Android
+     * to secure hardware.
+     */
+    SECURELY_IMPORTED = 4,
+};
+
+/**
+ * Usability requirements of key blobs.  This defines what system functionality must be available
+ * for the key to function.  For example, key "blobs" which are actually handles referencing
+ * encrypted key material stored in the file system cannot be used until the file system is
+ * available, and should have BLOB_REQUIRES_FILE_SYSTEM.
+ */
+enum KeyBlobUsageRequirements : uint32_t {
+    STANDALONE = 0,
+    REQUIRES_FILE_SYSTEM = 1,
+};
+
+/**
+ * Possible purposes of a key (or pair).
+ */
+enum KeyPurpose : uint32_t {
+    ENCRYPT = 0,    /* Usable with RSA, EC and AES keys. */
+    DECRYPT = 1,    /* Usable with RSA, EC and AES keys. */
+    SIGN = 2,       /* Usable with RSA, EC and HMAC keys. */
+    VERIFY = 3,     /* Usable with RSA, EC and HMAC keys. */
+    /* 4 is reserved */
+    WRAP_KEY = 5,   /* Usable with wrapping keys. */
+};
+
+/**
+ * Keymaster error codes.
+ */
+enum ErrorCode : int32_t {
+    OK = 0,
+    ROOT_OF_TRUST_ALREADY_SET = -1,
+    UNSUPPORTED_PURPOSE = -2,
+    INCOMPATIBLE_PURPOSE = -3,
+    UNSUPPORTED_ALGORITHM = -4,
+    INCOMPATIBLE_ALGORITHM = -5,
+    UNSUPPORTED_KEY_SIZE = -6,
+    UNSUPPORTED_BLOCK_MODE = -7,
+    INCOMPATIBLE_BLOCK_MODE = -8,
+    UNSUPPORTED_MAC_LENGTH = -9,
+    UNSUPPORTED_PADDING_MODE = -10,
+    INCOMPATIBLE_PADDING_MODE = -11,
+    UNSUPPORTED_DIGEST = -12,
+    INCOMPATIBLE_DIGEST = -13,
+    INVALID_EXPIRATION_TIME = -14,
+    INVALID_USER_ID = -15,
+    INVALID_AUTHORIZATION_TIMEOUT = -16,
+    UNSUPPORTED_KEY_FORMAT = -17,
+    INCOMPATIBLE_KEY_FORMAT = -18,
+    UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19,   /** For PKCS8 & PKCS12 */
+    UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20, /** For PKCS8 & PKCS12 */
+    INVALID_INPUT_LENGTH = -21,
+    KEY_EXPORT_OPTIONS_INVALID = -22,
+    DELEGATION_NOT_ALLOWED = -23,
+    KEY_NOT_YET_VALID = -24,
+    KEY_EXPIRED = -25,
+    KEY_USER_NOT_AUTHENTICATED = -26,
+    OUTPUT_PARAMETER_NULL = -27,
+    INVALID_OPERATION_HANDLE = -28,
+    INSUFFICIENT_BUFFER_SPACE = -29,
+    VERIFICATION_FAILED = -30,
+    TOO_MANY_OPERATIONS = -31,
+    UNEXPECTED_NULL_POINTER = -32,
+    INVALID_KEY_BLOB = -33,
+    IMPORTED_KEY_NOT_ENCRYPTED = -34,
+    IMPORTED_KEY_DECRYPTION_FAILED = -35,
+    IMPORTED_KEY_NOT_SIGNED = -36,
+    IMPORTED_KEY_VERIFICATION_FAILED = -37,
+    INVALID_ARGUMENT = -38,
+    UNSUPPORTED_TAG = -39,
+    INVALID_TAG = -40,
+    MEMORY_ALLOCATION_FAILED = -41,
+    IMPORT_PARAMETER_MISMATCH = -44,
+    SECURE_HW_ACCESS_DENIED = -45,
+    OPERATION_CANCELLED = -46,
+    CONCURRENT_ACCESS_CONFLICT = -47,
+    SECURE_HW_BUSY = -48,
+    SECURE_HW_COMMUNICATION_FAILED = -49,
+    UNSUPPORTED_EC_FIELD = -50,
+    MISSING_NONCE = -51,
+    INVALID_NONCE = -52,
+    MISSING_MAC_LENGTH = -53,
+    KEY_RATE_LIMIT_EXCEEDED = -54,
+    CALLER_NONCE_PROHIBITED = -55,
+    KEY_MAX_OPS_EXCEEDED = -56,
+    INVALID_MAC_LENGTH = -57,
+    MISSING_MIN_MAC_LENGTH = -58,
+    UNSUPPORTED_MIN_MAC_LENGTH = -59,
+    UNSUPPORTED_KDF = -60,
+    UNSUPPORTED_EC_CURVE = -61,
+    KEY_REQUIRES_UPGRADE = -62,
+    ATTESTATION_CHALLENGE_MISSING = -63,
+    KEYMASTER_NOT_CONFIGURED = -64,
+    ATTESTATION_APPLICATION_ID_MISSING = -65,
+    CANNOT_ATTEST_IDS = -66,
+    ROLLBACK_RESISTANCE_UNAVAILABLE = -67,
+    HARDWARE_TYPE_UNAVAILABLE = -68,
+    PROOF_OF_PRESENCE_REQUIRED = -69,
+    CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
+    NO_USER_CONFIRMATION = -71,
+
+    UNIMPLEMENTED = -100,
+    VERSION_MISMATCH = -101,
+
+    UNKNOWN_ERROR = -1000,
+};
+
+/**
+ * Key derivation functions, mostly used in ECIES.
+ */
+enum KeyDerivationFunction : uint32_t {
+    /** Do not apply a key derivation function; use the raw agreed key */
+    NONE = 0,
+    /** HKDF defined in RFC 5869 with SHA256 */
+    RFC5869_SHA256 = 1,
+    /** KDF1 defined in ISO 18033-2 with SHA1 */
+    ISO18033_2_KDF1_SHA1 = 2,
+    /** KDF1 defined in ISO 18033-2 with SHA256 */
+    ISO18033_2_KDF1_SHA256 = 3,
+    /** KDF2 defined in ISO 18033-2 with SHA1 */
+    ISO18033_2_KDF2_SHA1 = 4,
+    /** KDF2 defined in ISO 18033-2 with SHA256 */
+    ISO18033_2_KDF2_SHA256 = 5,
+};
+
+/**
+ * Hardware authentication type, used by HardwareAuthTokens to specify the mechanism used to
+ * authentiate the user, and in KeyCharacteristics to specify the allowable mechanisms for
+ * authenticating to activate a key.
+ */
+enum HardwareAuthenticatorType : uint32_t {
+    NONE = 0,
+    PASSWORD = 1 << 0,
+    FINGERPRINT = 1 << 1,
+    // Additional entries must be powers of 2.
+    ANY = 0xFFFFFFFF,
+};
+
+/**
+ * Device security levels.
+ */
+enum SecurityLevel : uint32_t {
+    SOFTWARE = 0,
+    TRUSTED_ENVIRONMENT = 1,
+    /**
+     * STRONGBOX specifies that the secure hardware satisfies the following requirements:
+     *
+     *    a) Has a discrete CPU.  The StrongBox device must not be the same CPU that is used to run
+     *       the Android non-secure world, or any other untrusted code.  The StrongBox CPU must not
+     *       share cache, RAM or any other critical resources with any device that runs untrusted
+     *       code.
+     *
+     *    b) Has integral secure storage.  The StrongBox device must have its own non-volatile
+     *       storage that is not accessible by any other hardware component.
+     *
+     *    c) Has a high-quality True Random Number Generator.  The StrongBox device must have sole
+     *       control of and access to a high-quality TRNG which it uses for generating necessary
+     *       random bits.  It must combine the output of this TRNG with caller-provided entropy in a
+     *       strong CPRNG, as do non-Strongbox Keymaster implementations.
+     *
+     *    d) Is enclosed in tamper-resistant packaging.  The StrongBox device must have
+     *       tamper-resistant packaging which provides obstacles to physical penetration which are
+     *       higher than those provided by normal integrated circuit packages.
+     *
+     *    e) Provides side-channel resistance.  The StrongBox device must implement resistance
+     *       against common side-channel attacks, including power analysis, timing analysis, EM
+     *       snooping, etc.
+     *
+     * Devices with StrongBox Keymasters must also have a non-StrongBox Keymaster, which lives in
+     * the higher-performance TEE.  Keystore must load both StrongBox (if available) and
+     * non-StrongBox HALs and route key generation/import requests appropriately.  Callers that want
+     * StrongBox keys must add Tag::HARDWARE_TYPE with value SecurityLevel::STRONGBOX to the key
+     * description provided to generateKey or importKey.  Keytore must route the request to a
+     * StrongBox HAL (a HAL whose isStrongBox method returns true).  Keymaster implementations that
+     * receive a request for a Tag::HARDWARE_TYPE that is inappropriate must fail with
+     * ErrorCode::HARDWARE_TYPE_UNAVAILABLE.
+     */
+    STRONGBOX = 2,              /* See IKeymaster::isStrongBox */
+};
+
+/**
+ * Formats for key import and export.
+ */
+enum KeyFormat : uint32_t {
+    /** X.509 certificate format, for public key export. */
+    X509 = 0,
+    /** PCKS#8 format, asymmetric key pair import. */
+    PKCS8 = 1,
+    /** Raw bytes, for symmetric key import and export. */
+    RAW = 3,
+};
+
+struct KeyParameter {
+    /**
+     * Discriminates the uinon/blob field used.  The blob cannot be coincided with the union, but
+     * only one of "f" and "blob" is ever used at a time. */
+    Tag tag;
+    union IntegerParams {
+        /** Enum types */
+        Algorithm algorithm;
+        BlockMode blockMode;
+        PaddingMode paddingMode;
+        Digest digest;
+        EcCurve ecCurve;
+        KeyOrigin origin;
+        KeyBlobUsageRequirements keyBlobUsageRequirements;
+        KeyPurpose purpose;
+        KeyDerivationFunction keyDerivationFunction;
+        HardwareAuthenticatorType hardwareAuthenticatorType;
+        SecurityLevel hardwareType;
+
+        /** Other types */
+        bool boolValue;  // Always true, if a boolean tag is present.
+        uint32_t integer;
+        uint64_t longInteger;
+        uint64_t dateTime;
+    };
+    IntegerParams f;  // Hidl does not support anonymous unions, so we have to name it.
+    vec<uint8_t> blob;
+};
+
+struct KeyCharacteristics {
+    vec<KeyParameter> softwareEnforced;
+    vec<KeyParameter> hardwareEnforced;
+};
+
+/**
+ * Data used to prove successful authentication.
+ */
+struct HardwareAuthToken {
+    uint64_t challenge;
+    uint64_t userId;             // Secure User ID, not Android user ID.
+    uint64_t authenticatorId;    // Secure authenticator ID.
+    HardwareAuthenticatorType authenticatorType;
+    Timestamp timestamp;
+    /**
+     * MACs are computed with a backward-compatible method, used by Keymaster 3.0, Gatekeeper 1.0
+     * and Fingerprint 1.0, as well as pre-treble HALs.
+     *
+     * The MAC is Constants::AUTH_TOKEN_MAC_LENGTH bytes in length and is computed as follows:
+     *
+     *     HMAC_SHA256(
+     *         H, 0 || challenge || user_id || authenticator_id || authenticator_type || timestamp)
+     *
+     * where ``||'' represents concatenation, the leading zero is a single byte, and all integers
+     * are represented as unsigned values, the full width of the type.  The challenge, userId and
+     * authenticatorId values are in machine order, but authenticatorType and timestamp are in
+     * network order.  This odd construction is compatible with the hw_auth_token_t structure,
+     *
+     * Note that mac is a vec rather than an array, not because it's actually variable-length but
+     * because it could be empty.  As documented in the IKeymasterDevice::begin,
+     * IKeymasterDevice::update and IKeymasterDevice::finish doc comments, an empty mac indicates
+     * that this auth token is empty.
+     */
+    vec<uint8_t> mac;
+};
+
+typedef uint64_t OperationHandle;
+
+/**
+ * HmacSharingParameters holds the data used in the process of establishing a shared HMAC key
+ * between multiple Keymaster instances.  Sharing parameters are returned in this struct by
+ * getHmacSharingParameters() and send to computeSharedHmac().  See the named methods in IKeymaster
+ * for details of usage.
+ */
+struct HmacSharingParameters {
+    /**
+     * Either empty or contains a persistent value that is associated with the pre-shared HMAC
+     * agreement key (see documentation of computeSharedHmac in @4.0::IKeymaster).  It is either
+     * empty or 32 bytes in length.
+     */
+    vec<uint8_t> seed;
+
+    /**
+     * A 32-byte value which is guaranteed to be different each time
+     * getHmacSharingParameters() is called.  Probabilistic uniqueness (i.e. random) is acceptable,
+     * though a stronger uniqueness guarantee (e.g. counter) is recommended where possible.
+     */
+    uint8_t[32] nonce;
+};
+
+/**
+ * VerificationToken enables one Keymaster instance to validate authorizations for another.  See
+ * verifyAuthorizations() in IKeymaster for details.
+ */
+struct VerificationToken {
+    /**
+     * The operation handle, used to ensure freshness.
+     */
+    uint64_t challenge;
+
+    /**
+     * The current time of the secure environment that generates the VerificationToken.  This can be
+     * checked against auth tokens generated by the same secure environment, which avoids needing to
+     * synchronize clocks.
+     */
+    Timestamp timestamp;
+
+    /**
+     * A list of the parameters verified.  Empty if the only parameters verified are time-related.
+     * In that case the timestamp is the payload.
+     */
+    vec<KeyParameter> parametersVerified;
+
+    /**
+     * SecurityLevel of the secure environment that generated the token.
+     */
+    SecurityLevel securityLevel;
+
+    /**
+     * 32-byte HMAC-SHA256 of the above values, computed as:
+     *
+     *    HMAC(H,
+     *         "Auth Verification" || challenge || timestamp || securityLevel || parametersVerified)
+     *
+     * where:
+     *
+     *   ``HMAC'' is the shared HMAC key (see computeSharedHmac() in IKeymaster).
+     *
+     *   ``||'' represents concatenation
+     *
+     * The representation of challenge and timestamp is as 64-bit unsigned integers in big-endian
+     * order.  securityLevel is represented as a 32-bit unsigned integer in big-endian order.
+     *
+     * If parametersVerified is non-empty, the representation of parametersVerified is an ASN.1 DER
+     * encoded representation of the values.  The ASN.1 schema used is the AuthorizationList schema
+     * from the Keystore attestation documentation.  If parametersVerified is empty, it is simply
+     * omitted from the HMAC computation.
+     */
+    vec<uint8_t> mac;
+};
diff --git a/keymaster/4.0/vts/OWNERS b/keymaster/4.0/vts/OWNERS
new file mode 100644
index 0000000..376c12b
--- /dev/null
+++ b/keymaster/4.0/vts/OWNERS
@@ -0,0 +1,4 @@
+jdanis@google.com
+swillden@google.com
+yim@google.com
+yuexima@google.com
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
new file mode 100644
index 0000000..d74a16f
--- /dev/null
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalKeymasterV4_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "HmacKeySharingTest.cpp",
+        "KeymasterHidlTest.cpp",
+        "VerificationTokenTest.cpp",
+        "keymaster_hidl_hal_test.cpp",
+    ],
+    static_libs: [
+        "android.hardware.keymaster@4.0",
+        "libcrypto",
+        "libkeymaster4support",
+        "libsoftkeymasterdevice",
+    ],
+}
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
new file mode 100644
index 0000000..96c47a8
--- /dev/null
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KeymasterHidlTest.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace test {
+
+/**
+ * HmacKeySharingTest extends KeymasterHidlTest with some utilities that make writing HMAC sharing
+ * tests easier.
+ */
+class HmacKeySharingTest : public KeymasterHidlTest {
+   protected:
+    struct GetParamsResult {
+        ErrorCode error;
+        HmacSharingParameters params;
+        auto tie() { return std::tie(error, params); }
+    };
+
+    struct ComputeHmacResult {
+        ErrorCode error;
+        HidlBuf sharing_check;
+        auto tie() { return std::tie(error, sharing_check); }
+    };
+
+    using KeymasterVec = std::vector<sp<IKeymasterDevice>>;
+    using ByteString = std::basic_string<uint8_t>;
+    // using NonceVec = std::vector<HidlBuf>;
+
+    GetParamsResult getHmacSharingParameters(IKeymasterDevice& keymaster) {
+        GetParamsResult result;
+        EXPECT_TRUE(keymaster
+                        .getHmacSharingParameters([&](auto error, auto params) {
+                            result.tie() = std::tie(error, params);
+                        })
+                        .isOk());
+        return result;
+    }
+
+    hidl_vec<HmacSharingParameters> getHmacSharingParameters(const KeymasterVec& keymasters) {
+        std::vector<HmacSharingParameters> paramsVec;
+        for (auto& keymaster : keymasters) {
+            auto result = getHmacSharingParameters(*keymaster);
+            EXPECT_EQ(ErrorCode::OK, result.error);
+            if (result.error == ErrorCode::OK) paramsVec.push_back(std::move(result.params));
+        }
+        return paramsVec;
+    }
+
+    ComputeHmacResult computeSharedHmac(IKeymasterDevice& keymaster,
+                                        const hidl_vec<HmacSharingParameters>& params) {
+        ComputeHmacResult result;
+        EXPECT_TRUE(keymaster
+                        .computeSharedHmac(params,
+                                           [&](auto error, auto params) {
+                                               result.tie() = std::tie(error, params);
+                                           })
+                        .isOk());
+        return result;
+    }
+
+    std::vector<ComputeHmacResult> computeSharedHmac(
+        const KeymasterVec& keymasters, const hidl_vec<HmacSharingParameters>& paramsVec) {
+        std::vector<ComputeHmacResult> resultVec;
+        for (auto& keymaster : keymasters) {
+            resultVec.push_back(computeSharedHmac(*keymaster, paramsVec));
+        }
+        return resultVec;
+    }
+
+    std::vector<ByteString> copyNonces(const hidl_vec<HmacSharingParameters>& paramsVec) {
+        std::vector<ByteString> nonces;
+        for (auto& param : paramsVec) {
+            nonces.emplace_back(param.nonce.data(), param.nonce.size());
+        }
+        return nonces;
+    }
+
+    void verifyResponses(const HidlBuf& expected, const std::vector<ComputeHmacResult>& responses) {
+        for (auto& response : responses) {
+            EXPECT_EQ(ErrorCode::OK, response.error);
+            EXPECT_EQ(expected, response.sharing_check) << "Sharing check values should match.";
+        }
+    }
+};
+
+TEST_F(HmacKeySharingTest, GetParameters) {
+    auto result1 = getHmacSharingParameters(keymaster());
+    EXPECT_EQ(ErrorCode::OK, result1.error);
+
+    auto result2 = getHmacSharingParameters(keymaster());
+    EXPECT_EQ(ErrorCode::OK, result2.error);
+
+    ASSERT_EQ(result1.params.seed, result2.params.seed)
+        << "A given keymaster should always return the same seed.";
+    ASSERT_EQ(result1.params.nonce, result2.params.nonce)
+        << "A given keymaster should always return the same nonce until restart.";
+}
+
+TEST_F(HmacKeySharingTest, ComputeSharedHmac) {
+    auto params = getHmacSharingParameters(all_keymasters());
+    ASSERT_EQ(all_keymasters().size(), params.size())
+        << "One or more keymasters failed to provide parameters.";
+
+    auto nonces = copyNonces(params);
+    EXPECT_EQ(all_keymasters().size(), nonces.size());
+    std::sort(nonces.begin(), nonces.end());
+    std::unique(nonces.begin(), nonces.end());
+    EXPECT_EQ(all_keymasters().size(), nonces.size());
+
+    auto responses = computeSharedHmac(all_keymasters(), params);
+    ASSERT_GT(responses.size(), 0U);
+    verifyResponses(responses[0].sharing_check, responses);
+
+    // Do it a second time.  Should get the same answers.
+    params = getHmacSharingParameters(all_keymasters());
+    ASSERT_EQ(all_keymasters().size(), params.size())
+        << "One or more keymasters failed to provide parameters.";
+
+    responses = computeSharedHmac(all_keymasters(), params);
+    ASSERT_GT(responses.size(), 0U);
+    verifyResponses(responses[0].sharing_check, responses);
+}
+
+template <class F>
+class final_action {
+   public:
+    explicit final_action(F f) : f_(move(f)) {}
+    ~final_action() { f_(); }
+
+   private:
+    F f_;
+};
+
+template <class F>
+inline final_action<F> finally(const F& f) {
+    return final_action<F>(f);
+}
+
+TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptNonce) {
+    // Important: The execution of this test gets the keymaster implementations on the device out of
+    // sync with respect to the HMAC key.  Granted that VTS tests aren't run on in-use production
+    // devices, this still has the potential to cause confusion.  To mitigate that, we always
+    // (barring crashes :-/) re-run the unmodified agreement process on our way out.
+    auto fixup_hmac = finally(
+        [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
+
+    auto params = getHmacSharingParameters(all_keymasters());
+    ASSERT_EQ(all_keymasters().size(), params.size())
+        << "One or more keymasters failed to provide parameters.";
+
+    // All should be well in the normal case
+    auto responses = computeSharedHmac(all_keymasters(), params);
+
+    ASSERT_GT(responses.size(), 0U);
+    HidlBuf correct_response = responses[0].sharing_check;
+    verifyResponses(correct_response, responses);
+
+    // Pick a random param, a random byte within the param's nonce, and a random bit within
+    // the byte.  Flip that bit.
+    size_t param_to_tweak = rand() % params.size();
+    uint8_t byte_to_tweak = rand() % sizeof(params[param_to_tweak].nonce);
+    uint8_t bit_to_tweak = rand() % 8;
+    params[param_to_tweak].nonce[byte_to_tweak] ^= (1 << bit_to_tweak);
+
+    responses = computeSharedHmac(all_keymasters(), params);
+    for (size_t i = 0; i < responses.size(); ++i) {
+        if (i == param_to_tweak) {
+            EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
+                << "Keymaster that provided tweaked param should fail to compute HMAC key";
+        } else {
+            EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
+            EXPECT_NE(correct_response, responses[i].sharing_check)
+                << "Others should calculate a different HMAC key, due to the tweaked nonce.";
+        }
+    }
+}
+
+TEST_F(HmacKeySharingTest, ComputeSharedHmacCorruptSeed) {
+    // Important: The execution of this test gets the keymaster implementations on the device out of
+    // sync with respect to the HMAC key.  Granted that VTS tests aren't run on in-use production
+    // devices, this still has the potential to cause confusion.  To mitigate that, we always
+    // (barring crashes :-/) re-run the unmodified agreement process on our way out.
+    auto fixup_hmac = finally(
+        [&]() { computeSharedHmac(all_keymasters(), getHmacSharingParameters(all_keymasters())); });
+
+    auto params = getHmacSharingParameters(all_keymasters());
+    ASSERT_EQ(all_keymasters().size(), params.size())
+        << "One or more keymasters failed to provide parameters.";
+
+    // All should be well in the normal case
+    auto responses = computeSharedHmac(all_keymasters(), params);
+
+    ASSERT_GT(responses.size(), 0U);
+    HidlBuf correct_response = responses[0].sharing_check;
+    verifyResponses(correct_response, responses);
+
+    // Pick a random param and modify the seed.  We just increase the seed length by 1.  It doesn't
+    // matter what value is in the additional byte; it changes the seed regardless.
+    auto param_to_tweak = rand() % params.size();
+    auto& to_tweak = params[param_to_tweak].seed;
+    to_tweak.resize(to_tweak.size() + 1);
+
+    responses = computeSharedHmac(all_keymasters(), params);
+    for (size_t i = 0; i < responses.size(); ++i) {
+        if (i == param_to_tweak) {
+            EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error)
+                << "Keymaster that provided tweaked param should fail to compute HMAC key ";
+        } else {
+            EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
+            EXPECT_NE(correct_response, responses[i].sharing_check)
+                << "Others should calculate a different HMAC key, due to the tweaked nonce.";
+        }
+    }
+}
+
+}  // namespace test
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
new file mode 100644
index 0000000..37d8c42
--- /dev/null
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.cpp
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KeymasterHidlTest.h"
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+
+#include <keymasterV4_0/key_param_output.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
+    if (set.size() == 0)
+        os << "(Empty)" << ::std::endl;
+    else {
+        os << "\n";
+        for (size_t i = 0; i < set.size(); ++i) os << set[i] << ::std::endl;
+    }
+    return os;
+}
+
+namespace test {
+
+sp<IKeymasterDevice> KeymasterHidlTest::keymaster_;
+std::vector<sp<IKeymasterDevice>> KeymasterHidlTest::all_keymasters_;
+uint32_t KeymasterHidlTest::os_version_;
+uint32_t KeymasterHidlTest::os_patch_level_;
+SecurityLevel KeymasterHidlTest::securityLevel_;
+hidl_string KeymasterHidlTest::name_;
+hidl_string KeymasterHidlTest::author_;
+
+void KeymasterHidlTest::SetUpTestCase() {
+    string service_name = KeymasterHidlEnvironment::Instance()->getServiceName<IKeymasterDevice>();
+    keymaster_ = ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(service_name);
+    ASSERT_NE(keymaster_, nullptr);
+
+    ASSERT_TRUE(keymaster_
+                    ->getHardwareInfo([&](SecurityLevel securityLevel, const hidl_string& name,
+                                          const hidl_string& author) {
+                        securityLevel_ = securityLevel;
+                        name_ = name;
+                        author_ = author;
+                    })
+                    .isOk());
+
+    os_version_ = ::keymaster::GetOsVersion();
+    os_patch_level_ = ::keymaster::GetOsPatchlevel();
+
+    auto service_manager = android::hidl::manager::V1_0::IServiceManager::getService();
+    ASSERT_NE(nullptr, service_manager.get());
+
+    all_keymasters_.push_back(keymaster_);
+    service_manager->listByInterface(
+        IKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) {
+            for (auto& name : names) {
+                if (name == service_name) continue;
+                auto keymaster =
+                    ::testing::VtsHalHidlTargetTestBase::getService<IKeymasterDevice>(name);
+                ASSERT_NE(keymaster, nullptr);
+                all_keymasters_.push_back(keymaster);
+            }
+        });
+}
+
+ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
+                                         KeyCharacteristics* key_characteristics) {
+    EXPECT_NE(key_blob, nullptr) << "Key blob pointer must not be null.  Test bug";
+    EXPECT_EQ(0U, key_blob->size()) << "Key blob not empty before generating key.  Test bug.";
+    EXPECT_NE(key_characteristics, nullptr)
+        << "Previous characteristics not deleted before generating key.  Test bug.";
+
+    ErrorCode error;
+    EXPECT_TRUE(keymaster_
+                    ->generateKey(key_desc.hidl_data(),
+                                  [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+                                      const KeyCharacteristics& hidl_key_characteristics) {
+                                      error = hidl_error;
+                                      *key_blob = hidl_key_blob;
+                                      *key_characteristics = hidl_key_characteristics;
+                                  })
+                    .isOk());
+    // On error, blob & characteristics should be empty.
+    if (error != ErrorCode::OK) {
+        EXPECT_EQ(0U, key_blob->size());
+        EXPECT_EQ(0U, (key_characteristics->softwareEnforced.size() +
+                       key_characteristics->hardwareEnforced.size()));
+    }
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::GenerateKey(const AuthorizationSet& key_desc) {
+    return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
+}
+
+ErrorCode KeymasterHidlTest::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+                                       const string& key_material, HidlBuf* key_blob,
+                                       KeyCharacteristics* key_characteristics) {
+    ErrorCode error;
+    EXPECT_TRUE(keymaster_
+                    ->importKey(key_desc.hidl_data(), format, HidlBuf(key_material),
+                                [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+                                    const KeyCharacteristics& hidl_key_characteristics) {
+                                    error = hidl_error;
+                                    *key_blob = hidl_key_blob;
+                                    *key_characteristics = hidl_key_characteristics;
+                                })
+                    .isOk());
+    // On error, blob & characteristics should be empty.
+    if (error != ErrorCode::OK) {
+        EXPECT_EQ(0U, key_blob->size());
+        EXPECT_EQ(0U, (key_characteristics->softwareEnforced.size() +
+                       key_characteristics->hardwareEnforced.size()));
+    }
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+                                       const string& key_material) {
+    return ImportKey(key_desc, format, key_material, &key_blob_, &key_characteristics_);
+}
+
+ErrorCode KeymasterHidlTest::ImportWrappedKey(string wrapped_key, string wrapping_key,
+                                              const AuthorizationSet& wrapping_key_desc,
+                                              string masking_key,
+                                              const AuthorizationSet& unwrapping_params) {
+    ErrorCode error;
+    ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key);
+    EXPECT_TRUE(keymaster_
+                    ->importWrappedKey(HidlBuf(wrapped_key), key_blob_, HidlBuf(masking_key),
+                                       unwrapping_params.hidl_data(), 0 /* passwordSid */,
+                                       0 /* biometricSid */,
+                                       [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+                                           const KeyCharacteristics& hidl_key_characteristics) {
+                                           error = hidl_error;
+                                           key_blob_ = hidl_key_blob;
+                                           key_characteristics_ = hidl_key_characteristics;
+                                       })
+                    .isOk());
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::ExportKey(KeyFormat format, const HidlBuf& key_blob,
+                                       const HidlBuf& client_id, const HidlBuf& app_data,
+                                       HidlBuf* key_material) {
+    ErrorCode error;
+    EXPECT_TRUE(keymaster_
+                    ->exportKey(format, key_blob, client_id, app_data,
+                                [&](ErrorCode hidl_error_code, const HidlBuf& hidl_key_material) {
+                                    error = hidl_error_code;
+                                    *key_material = hidl_key_material;
+                                })
+                    .isOk());
+    // On error, blob should be empty.
+    if (error != ErrorCode::OK) {
+        EXPECT_EQ(0U, key_material->size());
+    }
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::ExportKey(KeyFormat format, HidlBuf* key_material) {
+    HidlBuf client_id, app_data;
+    return ExportKey(format, key_blob_, client_id, app_data, key_material);
+}
+
+ErrorCode KeymasterHidlTest::DeleteKey(HidlBuf* key_blob, bool keep_key_blob) {
+    auto rc = keymaster_->deleteKey(*key_blob);
+    if (!keep_key_blob) *key_blob = HidlBuf();
+    if (!rc.isOk()) return ErrorCode::UNKNOWN_ERROR;
+    return rc;
+}
+
+ErrorCode KeymasterHidlTest::DeleteKey(bool keep_key_blob) {
+    return DeleteKey(&key_blob_, keep_key_blob);
+}
+
+ErrorCode KeymasterHidlTest::DeleteAllKeys() {
+    ErrorCode error = keymaster_->deleteAllKeys();
+    return error;
+}
+
+void KeymasterHidlTest::CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob) {
+    auto rc = DeleteKey(key_blob, keep_key_blob);
+    EXPECT_TRUE(rc == ErrorCode::OK || rc == ErrorCode::UNIMPLEMENTED);
+}
+
+void KeymasterHidlTest::CheckedDeleteKey() {
+    CheckedDeleteKey(&key_blob_);
+}
+
+ErrorCode KeymasterHidlTest::GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
+                                                const HidlBuf& app_data,
+                                                KeyCharacteristics* key_characteristics) {
+    ErrorCode error = ErrorCode::UNKNOWN_ERROR;
+    EXPECT_TRUE(
+        keymaster_
+            ->getKeyCharacteristics(
+                key_blob, client_id, app_data,
+                [&](ErrorCode hidl_error, const KeyCharacteristics& hidl_key_characteristics) {
+                    error = hidl_error, *key_characteristics = hidl_key_characteristics;
+                })
+            .isOk());
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::GetCharacteristics(const HidlBuf& key_blob,
+                                                KeyCharacteristics* key_characteristics) {
+    HidlBuf client_id, app_data;
+    return GetCharacteristics(key_blob, client_id, app_data, key_characteristics);
+}
+
+ErrorCode KeymasterHidlTest::Begin(KeyPurpose purpose, const HidlBuf& key_blob,
+                                   const AuthorizationSet& in_params, AuthorizationSet* out_params,
+                                   OperationHandle* op_handle) {
+    SCOPED_TRACE("Begin");
+    ErrorCode error;
+    OperationHandle saved_handle = *op_handle;
+    EXPECT_TRUE(keymaster_
+                    ->begin(purpose, key_blob, in_params.hidl_data(), HardwareAuthToken(),
+                            [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
+                                uint64_t hidl_op_handle) {
+                                error = hidl_error;
+                                *out_params = hidl_out_params;
+                                *op_handle = hidl_op_handle;
+                            })
+                    .isOk());
+    if (error != ErrorCode::OK) {
+        // Some implementations may modify *op_handle on error.
+        *op_handle = saved_handle;
+    }
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+                                   AuthorizationSet* out_params) {
+    SCOPED_TRACE("Begin");
+    EXPECT_EQ(kOpHandleSentinel, op_handle_);
+    return Begin(purpose, key_blob_, in_params, out_params, &op_handle_);
+}
+
+ErrorCode KeymasterHidlTest::Begin(KeyPurpose purpose, const AuthorizationSet& in_params) {
+    SCOPED_TRACE("Begin");
+    AuthorizationSet out_params;
+    ErrorCode error = Begin(purpose, in_params, &out_params);
+    EXPECT_TRUE(out_params.empty());
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::Update(OperationHandle op_handle, const AuthorizationSet& in_params,
+                                    const string& input, AuthorizationSet* out_params,
+                                    string* output, size_t* input_consumed) {
+    SCOPED_TRACE("Update");
+    ErrorCode error;
+    EXPECT_TRUE(keymaster_
+                    ->update(op_handle, in_params.hidl_data(), HidlBuf(input), HardwareAuthToken(),
+                             VerificationToken(),
+                             [&](ErrorCode hidl_error, uint32_t hidl_input_consumed,
+                                 const hidl_vec<KeyParameter>& hidl_out_params,
+                                 const HidlBuf& hidl_output) {
+                                 error = hidl_error;
+                                 out_params->push_back(AuthorizationSet(hidl_out_params));
+                                 output->append(hidl_output.to_string());
+                                 *input_consumed = hidl_input_consumed;
+                             })
+                    .isOk());
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::Update(const string& input, string* out, size_t* input_consumed) {
+    SCOPED_TRACE("Update");
+    AuthorizationSet out_params;
+    ErrorCode error = Update(op_handle_, AuthorizationSet() /* in_params */, input, &out_params,
+                             out, input_consumed);
+    EXPECT_TRUE(out_params.empty());
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::Finish(OperationHandle op_handle, const AuthorizationSet& in_params,
+                                    const string& input, const string& signature,
+                                    AuthorizationSet* out_params, string* output) {
+    SCOPED_TRACE("Finish");
+    ErrorCode error;
+    EXPECT_TRUE(
+        keymaster_
+            ->finish(op_handle, in_params.hidl_data(), HidlBuf(input), HidlBuf(signature),
+                     HardwareAuthToken(), VerificationToken(),
+                     [&](ErrorCode hidl_error, const hidl_vec<KeyParameter>& hidl_out_params,
+                         const HidlBuf& hidl_output) {
+                         error = hidl_error;
+                         *out_params = hidl_out_params;
+                         output->append(hidl_output.to_string());
+                     })
+            .isOk());
+    op_handle_ = kOpHandleSentinel;  // So dtor doesn't Abort().
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::Finish(const string& message, string* output) {
+    SCOPED_TRACE("Finish");
+    AuthorizationSet out_params;
+    string finish_output;
+    ErrorCode error = Finish(op_handle_, AuthorizationSet() /* in_params */, message,
+                             "" /* signature */, &out_params, output);
+    if (error != ErrorCode::OK) {
+        return error;
+    }
+    EXPECT_EQ(0U, out_params.size());
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::Finish(const string& message, const string& signature,
+                                    string* output) {
+    SCOPED_TRACE("Finish");
+    AuthorizationSet out_params;
+    ErrorCode error = Finish(op_handle_, AuthorizationSet() /* in_params */, message, signature,
+                             &out_params, output);
+    op_handle_ = kOpHandleSentinel;  // So dtor doesn't Abort().
+    if (error != ErrorCode::OK) {
+        return error;
+    }
+    EXPECT_EQ(0U, out_params.size());
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::Abort(OperationHandle op_handle) {
+    SCOPED_TRACE("Abort");
+    auto retval = keymaster_->abort(op_handle);
+    EXPECT_TRUE(retval.isOk());
+    return retval;
+}
+
+void KeymasterHidlTest::AbortIfNeeded() {
+    SCOPED_TRACE("AbortIfNeeded");
+    if (op_handle_ != kOpHandleSentinel) {
+        EXPECT_EQ(ErrorCode::OK, Abort(op_handle_));
+        op_handle_ = kOpHandleSentinel;
+    }
+}
+
+ErrorCode KeymasterHidlTest::AttestKey(const HidlBuf& key_blob,
+                                       const AuthorizationSet& attest_params,
+                                       hidl_vec<hidl_vec<uint8_t>>* cert_chain) {
+    SCOPED_TRACE("AttestKey");
+    ErrorCode error;
+    auto rc = keymaster_->attestKey(
+        key_blob, attest_params.hidl_data(),
+        [&](ErrorCode hidl_error, const hidl_vec<hidl_vec<uint8_t>>& hidl_cert_chain) {
+            error = hidl_error;
+            *cert_chain = hidl_cert_chain;
+        });
+
+    EXPECT_TRUE(rc.isOk()) << rc.description();
+    if (!rc.isOk()) return ErrorCode::UNKNOWN_ERROR;
+
+    return error;
+}
+
+ErrorCode KeymasterHidlTest::AttestKey(const AuthorizationSet& attest_params,
+                                       hidl_vec<hidl_vec<uint8_t>>* cert_chain) {
+    SCOPED_TRACE("AttestKey");
+    return AttestKey(key_blob_, attest_params, cert_chain);
+}
+
+string KeymasterHidlTest::ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation,
+                                         const string& message, const AuthorizationSet& in_params,
+                                         AuthorizationSet* out_params) {
+    SCOPED_TRACE("ProcessMessage");
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(operation, key_blob, in_params, &begin_out_params, &op_handle_));
+
+    string unused;
+    AuthorizationSet finish_params;
+    AuthorizationSet finish_out_params;
+    string output;
+    EXPECT_EQ(ErrorCode::OK,
+              Finish(op_handle_, finish_params, message, unused, &finish_out_params, &output));
+    op_handle_ = kOpHandleSentinel;
+
+    out_params->push_back(begin_out_params);
+    out_params->push_back(finish_out_params);
+    return output;
+}
+
+string KeymasterHidlTest::SignMessage(const HidlBuf& key_blob, const string& message,
+                                      const AuthorizationSet& params) {
+    SCOPED_TRACE("SignMessage");
+    AuthorizationSet out_params;
+    string signature = ProcessMessage(key_blob, KeyPurpose::SIGN, message, params, &out_params);
+    EXPECT_TRUE(out_params.empty());
+    return signature;
+}
+
+string KeymasterHidlTest::SignMessage(const string& message, const AuthorizationSet& params) {
+    SCOPED_TRACE("SignMessage");
+    return SignMessage(key_blob_, message, params);
+}
+
+string KeymasterHidlTest::MacMessage(const string& message, Digest digest, size_t mac_length) {
+    SCOPED_TRACE("MacMessage");
+    return SignMessage(
+        key_blob_, message,
+        AuthorizationSetBuilder().Digest(digest).Authorization(TAG_MAC_LENGTH, mac_length));
+}
+
+void KeymasterHidlTest::CheckHmacTestVector(const string& key, const string& message, Digest digest,
+                                            const string& expected_mac) {
+    SCOPED_TRACE("CheckHmacTestVector");
+    ASSERT_EQ(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .HmacKey(key.size() * 8)
+                            .Authorization(TAG_MIN_MAC_LENGTH, expected_mac.size() * 8)
+                            .Digest(digest),
+                        KeyFormat::RAW, key));
+    string signature = MacMessage(message, digest, expected_mac.size() * 8);
+    EXPECT_EQ(expected_mac, signature)
+        << "Test vector didn't match for key of size " << key.size() << " message of size "
+        << message.size() << " and digest " << digest;
+    CheckedDeleteKey();
+}
+
+void KeymasterHidlTest::CheckAesCtrTestVector(const string& key, const string& nonce,
+                                              const string& message,
+                                              const string& expected_ciphertext) {
+    SCOPED_TRACE("CheckAesCtrTestVector");
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .AesEncryptionKey(key.size() * 8)
+                                           .BlockMode(BlockMode::CTR)
+                                           .Authorization(TAG_CALLER_NONCE)
+                                           .Padding(PaddingMode::NONE),
+                                       KeyFormat::RAW, key));
+
+    auto params = AuthorizationSetBuilder()
+                      .Authorization(TAG_NONCE, nonce.data(), nonce.size())
+                      .BlockMode(BlockMode::CTR)
+                      .Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(key_blob_, message, params, &out_params);
+    EXPECT_EQ(expected_ciphertext, ciphertext);
+}
+
+void KeymasterHidlTest::CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode,
+                                                 PaddingMode padding_mode, const string& key,
+                                                 const string& iv, const string& input,
+                                                 const string& expected_output) {
+    auto authset = AuthorizationSetBuilder()
+                       .TripleDesEncryptionKey(key.size() * 7)
+                       .BlockMode(block_mode)
+                       .Padding(padding_mode);
+    if (iv.size()) authset.Authorization(TAG_CALLER_NONCE);
+    ASSERT_EQ(ErrorCode::OK, ImportKey(authset, KeyFormat::RAW, key));
+    auto begin_params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding_mode);
+    if (iv.size()) begin_params.Authorization(TAG_NONCE, iv.data(), iv.size());
+    AuthorizationSet output_params;
+    string output = ProcessMessage(key_blob_, purpose, input, begin_params, &output_params);
+    EXPECT_EQ(expected_output, output);
+}
+
+void KeymasterHidlTest::VerifyMessage(const HidlBuf& key_blob, const string& message,
+                                      const string& signature, const AuthorizationSet& params) {
+    SCOPED_TRACE("VerifyMessage");
+    AuthorizationSet begin_out_params;
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::VERIFY, key_blob, params, &begin_out_params, &op_handle_));
+
+    string unused;
+    AuthorizationSet finish_params;
+    AuthorizationSet finish_out_params;
+    string output;
+    EXPECT_EQ(ErrorCode::OK,
+              Finish(op_handle_, finish_params, message, signature, &finish_out_params, &output));
+    op_handle_ = kOpHandleSentinel;
+    EXPECT_TRUE(output.empty());
+}
+
+void KeymasterHidlTest::VerifyMessage(const string& message, const string& signature,
+                                      const AuthorizationSet& params) {
+    SCOPED_TRACE("VerifyMessage");
+    VerifyMessage(key_blob_, message, signature, params);
+}
+
+string KeymasterHidlTest::EncryptMessage(const HidlBuf& key_blob, const string& message,
+                                         const AuthorizationSet& in_params,
+                                         AuthorizationSet* out_params) {
+    SCOPED_TRACE("EncryptMessage");
+    return ProcessMessage(key_blob, KeyPurpose::ENCRYPT, message, in_params, out_params);
+}
+
+string KeymasterHidlTest::EncryptMessage(const string& message, const AuthorizationSet& params,
+                                         AuthorizationSet* out_params) {
+    SCOPED_TRACE("EncryptMessage");
+    return EncryptMessage(key_blob_, message, params, out_params);
+}
+
+string KeymasterHidlTest::EncryptMessage(const string& message, const AuthorizationSet& params) {
+    SCOPED_TRACE("EncryptMessage");
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_TRUE(out_params.empty()) << "Output params should be empty. Contained: " << out_params;
+    return ciphertext;
+}
+
+string KeymasterHidlTest::EncryptMessage(const string& message, BlockMode block_mode,
+                                         PaddingMode padding) {
+    SCOPED_TRACE("EncryptMessage");
+    auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_TRUE(out_params.empty()) << "Output params should be empty. Contained: " << out_params;
+    return ciphertext;
+}
+
+string KeymasterHidlTest::EncryptMessage(const string& message, BlockMode block_mode,
+                                         PaddingMode padding, HidlBuf* iv_out) {
+    SCOPED_TRACE("EncryptMessage");
+    auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_EQ(1U, out_params.size());
+    auto ivVal = out_params.GetTagValue(TAG_NONCE);
+    EXPECT_TRUE(ivVal.isOk());
+    *iv_out = ivVal.value();
+    return ciphertext;
+}
+
+string KeymasterHidlTest::EncryptMessage(const string& message, BlockMode block_mode,
+                                         PaddingMode padding, const HidlBuf& iv_in) {
+    SCOPED_TRACE("EncryptMessage");
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(block_mode)
+                      .Padding(padding)
+                      .Authorization(TAG_NONCE, iv_in);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    return ciphertext;
+}
+
+string KeymasterHidlTest::DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
+                                         const AuthorizationSet& params) {
+    SCOPED_TRACE("DecryptMessage");
+    AuthorizationSet out_params;
+    string plaintext =
+        ProcessMessage(key_blob, KeyPurpose::DECRYPT, ciphertext, params, &out_params);
+    EXPECT_TRUE(out_params.empty());
+    return plaintext;
+}
+
+string KeymasterHidlTest::DecryptMessage(const string& ciphertext, const AuthorizationSet& params) {
+    SCOPED_TRACE("DecryptMessage");
+    return DecryptMessage(key_blob_, ciphertext, params);
+}
+
+string KeymasterHidlTest::DecryptMessage(const string& ciphertext, BlockMode block_mode,
+                                         PaddingMode padding_mode, const HidlBuf& iv) {
+    SCOPED_TRACE("DecryptMessage");
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(block_mode)
+                      .Padding(padding_mode)
+                      .Authorization(TAG_NONCE, iv);
+    return DecryptMessage(key_blob_, ciphertext, params);
+}
+
+std::pair<ErrorCode, HidlBuf> KeymasterHidlTest::UpgradeKey(const HidlBuf& key_blob) {
+    std::pair<ErrorCode, HidlBuf> retval;
+    keymaster_->upgradeKey(key_blob, hidl_vec<KeyParameter>(),
+                           [&](ErrorCode error, const hidl_vec<uint8_t>& upgraded_blob) {
+                               retval = std::tie(error, upgraded_blob);
+                           });
+    return retval;
+}
+
+}  // namespace test
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/vts/functional/KeymasterHidlTest.h b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
new file mode 100644
index 0000000..36d3fc2
--- /dev/null
+++ b/keymaster/4.0/vts/functional/KeymasterHidlTest.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
+
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+#include <android/hardware/keymaster/4.0/types.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <keymaster/keymaster_configuration.h>
+
+#include <keymasterV4_0/authorization_set.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+
+::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set);
+
+namespace test {
+
+using ::android::sp;
+using ::std::string;
+
+class HidlBuf : public hidl_vec<uint8_t> {
+    typedef hidl_vec<uint8_t> super;
+
+   public:
+    HidlBuf() {}
+    HidlBuf(const super& other) : super(other) {}
+    HidlBuf(super&& other) : super(std::move(other)) {}
+    explicit HidlBuf(const std::string& other) : HidlBuf() { *this = other; }
+
+    HidlBuf& operator=(const super& other) {
+        super::operator=(other);
+        return *this;
+    }
+
+    HidlBuf& operator=(super&& other) {
+        super::operator=(std::move(other));
+        return *this;
+    }
+
+    HidlBuf& operator=(const string& other) {
+        resize(other.size());
+        std::copy(other.begin(), other.end(), begin());
+        return *this;
+    }
+
+    string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
+};
+
+constexpr uint64_t kOpHandleSentinel = 0xFFFFFFFFFFFFFFFF;
+
+class KeymasterHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static KeymasterHidlEnvironment* Instance() {
+        static KeymasterHidlEnvironment* instance = new KeymasterHidlEnvironment;
+        return instance;
+    }
+
+    void registerTestServices() override { registerTestService<IKeymasterDevice>(); }
+
+   private:
+    KeymasterHidlEnvironment(){};
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(KeymasterHidlEnvironment);
+};
+
+class KeymasterHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    void TearDown() override {
+        if (key_blob_.size()) {
+            CheckedDeleteKey();
+        }
+        AbortIfNeeded();
+    }
+
+    // SetUpTestCase runs only once per test case, not once per test.
+    static void SetUpTestCase();
+    static void TearDownTestCase() {
+        keymaster_.clear();
+        all_keymasters_.clear();
+    }
+
+    static IKeymasterDevice& keymaster() { return *keymaster_; }
+    static const std::vector<sp<IKeymasterDevice>>& all_keymasters() { return all_keymasters_; }
+    static uint32_t os_version() { return os_version_; }
+    static uint32_t os_patch_level() { return os_patch_level_; }
+
+    ErrorCode GenerateKey(const AuthorizationSet& key_desc, HidlBuf* key_blob,
+                          KeyCharacteristics* key_characteristics);
+    ErrorCode GenerateKey(const AuthorizationSet& key_desc);
+
+    ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+                        const string& key_material, HidlBuf* key_blob,
+                        KeyCharacteristics* key_characteristics);
+    ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
+                        const string& key_material);
+
+    ErrorCode ImportWrappedKey(string wrapped_key, string wrapping_key,
+                               const AuthorizationSet& wrapping_key_desc, string masking_key,
+                               const AuthorizationSet& unwrapping_params);
+
+    ErrorCode ExportKey(KeyFormat format, const HidlBuf& key_blob, const HidlBuf& client_id,
+                        const HidlBuf& app_data, HidlBuf* key_material);
+    ErrorCode ExportKey(KeyFormat format, HidlBuf* key_material);
+
+    ErrorCode DeleteKey(HidlBuf* key_blob, bool keep_key_blob = false);
+    ErrorCode DeleteKey(bool keep_key_blob = false);
+
+    ErrorCode DeleteAllKeys();
+
+    void CheckedDeleteKey(HidlBuf* key_blob, bool keep_key_blob = false);
+    void CheckedDeleteKey();
+
+    ErrorCode GetCharacteristics(const HidlBuf& key_blob, const HidlBuf& client_id,
+                                 const HidlBuf& app_data, KeyCharacteristics* key_characteristics);
+    ErrorCode GetCharacteristics(const HidlBuf& key_blob, KeyCharacteristics* key_characteristics);
+
+    ErrorCode Begin(KeyPurpose purpose, const HidlBuf& key_blob, const AuthorizationSet& in_params,
+                    AuthorizationSet* out_params, OperationHandle* op_handle);
+    ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+                    AuthorizationSet* out_params);
+    ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params);
+
+    ErrorCode Update(OperationHandle op_handle, const AuthorizationSet& in_params,
+                     const string& input, AuthorizationSet* out_params, string* output,
+                     size_t* input_consumed);
+    ErrorCode Update(const string& input, string* out, size_t* input_consumed);
+
+    ErrorCode Finish(OperationHandle op_handle, const AuthorizationSet& in_params,
+                     const string& input, const string& signature, AuthorizationSet* out_params,
+                     string* output);
+    ErrorCode Finish(const string& message, string* output);
+    ErrorCode Finish(const string& message, const string& signature, string* output);
+    ErrorCode Finish(string* output) { return Finish(string(), output); }
+
+    ErrorCode Abort(OperationHandle op_handle);
+
+    void AbortIfNeeded();
+
+    ErrorCode AttestKey(const HidlBuf& key_blob, const AuthorizationSet& attest_params,
+                        hidl_vec<hidl_vec<uint8_t>>* cert_chain);
+    ErrorCode AttestKey(const AuthorizationSet& attest_params,
+                        hidl_vec<hidl_vec<uint8_t>>* cert_chain);
+
+    string ProcessMessage(const HidlBuf& key_blob, KeyPurpose operation, const string& message,
+                          const AuthorizationSet& in_params, AuthorizationSet* out_params);
+
+    string SignMessage(const HidlBuf& key_blob, const string& message,
+                       const AuthorizationSet& params);
+    string SignMessage(const string& message, const AuthorizationSet& params);
+
+    string MacMessage(const string& message, Digest digest, size_t mac_length);
+
+    void CheckHmacTestVector(const string& key, const string& message, Digest digest,
+                             const string& expected_mac);
+
+    void CheckAesCtrTestVector(const string& key, const string& nonce, const string& message,
+                               const string& expected_ciphertext);
+
+    void CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode,
+                                  PaddingMode padding_mode, const string& key, const string& iv,
+                                  const string& input, const string& expected_output);
+
+    void VerifyMessage(const HidlBuf& key_blob, const string& message, const string& signature,
+                       const AuthorizationSet& params);
+    void VerifyMessage(const string& message, const string& signature,
+                       const AuthorizationSet& params);
+
+    string EncryptMessage(const HidlBuf& key_blob, const string& message,
+                          const AuthorizationSet& in_params, AuthorizationSet* out_params);
+    string EncryptMessage(const string& message, const AuthorizationSet& params,
+                          AuthorizationSet* out_params);
+    string EncryptMessage(const string& message, const AuthorizationSet& params);
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding);
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+                          HidlBuf* iv_out);
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+                          const HidlBuf& iv_in);
+
+    string DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
+                          const AuthorizationSet& params);
+    string DecryptMessage(const string& ciphertext, const AuthorizationSet& params);
+    string DecryptMessage(const string& ciphertext, BlockMode block_mode, PaddingMode padding_mode,
+                          const HidlBuf& iv);
+
+    std::pair<ErrorCode, HidlBuf> UpgradeKey(const HidlBuf& key_blob);
+
+    static bool IsSecure() { return securityLevel_ != SecurityLevel::SOFTWARE; }
+    static SecurityLevel SecLevel() { return securityLevel_; }
+
+    HidlBuf key_blob_;
+    KeyCharacteristics key_characteristics_;
+    OperationHandle op_handle_ = kOpHandleSentinel;
+
+   private:
+    static sp<IKeymasterDevice> keymaster_;
+    static std::vector<sp<IKeymasterDevice>> all_keymasters_;
+    static uint32_t os_version_;
+    static uint32_t os_patch_level_;
+
+    static SecurityLevel securityLevel_;
+    static hidl_string name_;
+    static hidl_string author_;
+};
+
+}  // namespace test
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_VTS_FUNCTIONAL_KEYMASTER_HIDL_TEST_H_
diff --git a/keymaster/4.0/vts/functional/VerificationTokenTest.cpp b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
new file mode 100644
index 0000000..6afba0c
--- /dev/null
+++ b/keymaster/4.0/vts/functional/VerificationTokenTest.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KeymasterHidlTest.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace test {
+
+class VerificationTokenTest : public KeymasterHidlTest {
+   protected:
+    struct VerifyAuthorizationResult {
+        bool callSuccessful;
+        ErrorCode error;
+        VerificationToken token;
+    };
+
+    VerifyAuthorizationResult verifyAuthorization(uint64_t operationHandle,
+                                                  const AuthorizationSet& paramsToVerify,
+                                                  const HardwareAuthToken& authToken) {
+        VerifyAuthorizationResult result;
+        result.callSuccessful =
+            keymaster()
+                .verifyAuthorization(operationHandle, paramsToVerify.hidl_data(), authToken,
+                                     [&](auto error, auto token) {
+                                         result.error = error;
+                                         result.token = token;
+                                     })
+                .isOk();
+        return result;
+    }
+
+    uint64_t getTime() {
+        struct timespec timespec;
+        EXPECT_EQ(0, clock_gettime(CLOCK_BOOTTIME, &timespec));
+        return timespec.tv_sec * 1000 + timespec.tv_nsec / 1000000;
+    }
+
+    int sleep_ms(uint32_t milliseconds) {
+        struct timespec sleep_time = {static_cast<time_t>(milliseconds / 1000),
+                                      static_cast<long>(milliseconds % 1000) * 1000000};
+        while (sleep_time.tv_sec || sleep_time.tv_nsec) {
+            if (nanosleep(&sleep_time /* to wait */,
+                          &sleep_time /* remaining (on interrruption) */) == 0) {
+                sleep_time = {};
+            } else {
+                if (errno != EINTR) return errno;
+            }
+        }
+        return 0;
+    }
+
+};  // namespace test
+
+/*
+ * VerificationTokens exist to facilitate cross-Keymaster verification of requirements.  As
+ * such, the precise capabilities required will vary depending on the specific vendor
+ * implementations. Essentially, VerificationTokens are a "hook" to enable vendor
+ * implementations to communicate, so the precise usage is defined by those vendors.  The only
+ * thing we really can test is that tokens can be created by TEE keymasters, and that the
+ * timestamps increase as expected.
+ */
+TEST_F(VerificationTokenTest, TestCreation) {
+    auto result1 = verifyAuthorization(
+        1 /* operation handle */, AuthorizationSet() /* paramtersToVerify */, HardwareAuthToken());
+    ASSERT_TRUE(result1.callSuccessful);
+    auto result1_time = getTime();
+
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        // StrongBox should not implement verifyAuthorization.
+        EXPECT_EQ(ErrorCode::UNIMPLEMENTED, result1.error);
+        return;
+    }
+
+    EXPECT_EQ(ErrorCode::OK, result1.error);
+    EXPECT_EQ(1U, result1.token.challenge);
+    EXPECT_EQ(SecLevel(), result1.token.securityLevel);
+    EXPECT_EQ(0U, result1.token.parametersVerified.size())
+        << "We didn't supply any parameters to verify";
+    EXPECT_GT(result1.token.timestamp, 0U);
+
+    constexpr uint32_t time_to_sleep = 200;
+    sleep_ms(time_to_sleep);
+
+    auto result2 = verifyAuthorization(
+        2 /* operation handle */, AuthorizationSet() /* paramtersToVerify */, HardwareAuthToken());
+    ASSERT_TRUE(result2.callSuccessful);
+    auto result2_time = getTime();
+    EXPECT_EQ(ErrorCode::OK, result2.error);
+    EXPECT_EQ(2U, result2.token.challenge);
+    EXPECT_EQ(SecLevel(), result2.token.securityLevel);
+    EXPECT_EQ(0U, result2.token.parametersVerified.size())
+        << "We didn't supply any parameters to verify";
+
+    auto host_time_delta = result2_time - result1_time;
+
+    EXPECT_GE(host_time_delta, time_to_sleep)
+        << "We slept for " << time_to_sleep << " ms, the clock must have advanced by that much";
+    EXPECT_LE(host_time_delta, time_to_sleep + 10)
+        << "The verifyAuthorization call took more than 10 ms?  That's awful!";
+
+    auto km_time_delta = result2.token.timestamp - result1.token.timestamp;
+
+    // If not too much else is going on on the system, the time delta should be quite close.  Allow
+    // 2 ms of slop just to avoid test flakiness.
+    //
+    // TODO(swillden): see if we can output values so they can be gathered across many runs and
+    // report if times aren't nearly always <1ms apart.
+    EXPECT_LE(host_time_delta, km_time_delta + 2);
+    EXPECT_LE(km_time_delta, host_time_delta + 2);
+}
+
+}  // namespace test
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
new file mode 100644
index 0000000..dbf5ece
--- /dev/null
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -0,0 +1,4137 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "keymaster_hidl_hal_test"
+#include <cutils/log.h>
+
+#include <iostream>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include <cutils/properties.h>
+
+#include <keymasterV4_0/attestation_record.h>
+#include <keymasterV4_0/key_param_output.h>
+#include <keymasterV4_0/openssl_utils.h>
+
+#include "KeymasterHidlTest.h"
+
+static bool arm_deleteAllKeys = false;
+static bool dump_Attestations = false;
+
+namespace android {
+namespace hardware {
+
+template <typename T>
+bool operator==(const hidl_vec<T>& a, const hidl_vec<T>& b) {
+    if (a.size() != b.size()) {
+        return false;
+    }
+    for (size_t i = 0; i < a.size(); ++i) {
+        if (a[i] != b[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+namespace keymaster {
+namespace V4_0 {
+
+bool operator==(const AuthorizationSet& a, const AuthorizationSet& b) {
+    return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+}
+
+bool operator==(const KeyCharacteristics& a, const KeyCharacteristics& b) {
+    // This isn't very efficient. Oh, well.
+    AuthorizationSet a_sw(a.softwareEnforced);
+    AuthorizationSet b_sw(b.softwareEnforced);
+    AuthorizationSet a_tee(b.hardwareEnforced);
+    AuthorizationSet b_tee(b.hardwareEnforced);
+
+    a_sw.Sort();
+    b_sw.Sort();
+    a_tee.Sort();
+    b_tee.Sort();
+
+    return a_sw == b_sw && a_tee == b_tee;
+}
+
+namespace test {
+namespace {
+
+template <TagType tag_type, Tag tag, typename ValueT>
+bool contains(hidl_vec<KeyParameter>& set, TypedTag<tag_type, tag> ttag, ValueT expected_value) {
+    size_t count = std::count_if(set.begin(), set.end(), [&](const KeyParameter& param) {
+        return param.tag == tag && accessTagValue(ttag, param) == expected_value;
+    });
+    return count == 1;
+}
+
+template <TagType tag_type, Tag tag>
+bool contains(hidl_vec<KeyParameter>& set, TypedTag<tag_type, tag>) {
+    size_t count = std::count_if(set.begin(), set.end(),
+                                 [&](const KeyParameter& param) { return param.tag == tag; });
+    return count > 0;
+}
+
+constexpr char hex_value[256] = {0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 1,  2,  3,  4,  5,  6,  7, 8, 9, 0, 0, 0, 0, 0, 0,  // '0'..'9'
+                                 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'A'..'F'
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 'a'..'f'
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0,  //
+                                 0, 0,  0,  0,  0,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+string hex2str(string a) {
+    string b;
+    size_t num = a.size() / 2;
+    b.resize(num);
+    for (size_t i = 0; i < num; i++) {
+        b[i] = (hex_value[a[i * 2] & 0xFF] << 4) + (hex_value[a[i * 2 + 1] & 0xFF]);
+    }
+    return b;
+}
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+string bin2hex(const hidl_vec<uint8_t>& data) {
+    string retval;
+    retval.reserve(data.size() * 2 + 1);
+    for (uint8_t byte : data) {
+        retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
+        retval.push_back(nibble2hex[0x0F & byte]);
+    }
+    return retval;
+}
+
+string rsa_key = hex2str(
+    "30820275020100300d06092a864886f70d01010105000482025f3082025b"
+    "02010002818100c6095409047d8634812d5a218176e45c41d60a75b13901"
+    "f234226cffe776521c5a77b9e389417b71c0b6a44d13afe4e4a2805d46c9"
+    "da2935adb1ff0c1f24ea06e62b20d776430a4d435157233c6f916783c30e"
+    "310fcbd89b85c2d56771169785ac12bca244abda72bfb19fc44d27c81e1d"
+    "92de284f4061edfd99280745ea6d2502030100010281801be0f04d9cae37"
+    "18691f035338308e91564b55899ffb5084d2460e6630257e05b3ceab0297"
+    "2dfabcd6ce5f6ee2589eb67911ed0fac16e43a444b8c861e544a05933657"
+    "72f8baf6b22fc9e3c5f1024b063ac080a7b2234cf8aee8f6c47bbf4fd3ac"
+    "e7240290bef16c0b3f7f3cdd64ce3ab5912cf6e32f39ab188358afcccd80"
+    "81024100e4b49ef50f765d3b24dde01aceaaf130f2c76670a91a61ae08af"
+    "497b4a82be6dee8fcdd5e3f7ba1cfb1f0c926b88f88c92bfab137fba2285"
+    "227b83c342ff7c55024100ddabb5839c4c7f6bf3d4183231f005b31aa58a"
+    "ffdda5c79e4cce217f6bc930dbe563d480706c24e9ebfcab28a6cdefd324"
+    "b77e1bf7251b709092c24ff501fd91024023d4340eda3445d8cd26c14411"
+    "da6fdca63c1ccd4b80a98ad52b78cc8ad8beb2842c1d280405bc2f6c1bea"
+    "214a1d742ab996b35b63a82a5e470fa88dbf823cdd02401b7b57449ad30d"
+    "1518249a5f56bb98294d4b6ac12ffc86940497a5a5837a6cf946262b4945"
+    "26d328c11e1126380fde04c24f916dec250892db09a6d77cdba351024077"
+    "62cd8f4d050da56bd591adb515d24d7ccd32cca0d05f866d583514bd7324"
+    "d5f33645e8ed8b4a1cb3cc4a1d67987399f2a09f5b3fb68c88d5e5d90ac3"
+    "3492d6");
+
+string ec_256_key = hex2str(
+    "308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
+    "6b0201010420737c2ecd7b8d1940bf2930aa9b4ed3ff941eed09366bc032"
+    "99986481f3a4d859a14403420004bf85d7720d07c25461683bc648b4778a"
+    "9a14dd8a024e3bdd8c7ddd9ab2b528bbc7aa1b51f14ebbbb0bd0ce21bcc4"
+    "1c6eb00083cf3376d11fd44949e0b2183bfe");
+
+string ec_521_key = hex2str(
+    "3081EE020100301006072A8648CE3D020106052B810400230481D63081D3"
+    "02010104420011458C586DB5DAA92AFAB03F4FE46AA9D9C3CE9A9B7A006A"
+    "8384BEC4C78E8E9D18D7D08B5BCFA0E53C75B064AD51C449BAE0258D54B9"
+    "4B1E885DED08ED4FB25CE9A1818903818600040149EC11C6DF0FA122C6A9"
+    "AFD9754A4FA9513A627CA329E349535A5629875A8ADFBE27DCB932C05198"
+    "6377108D054C28C6F39B6F2C9AF81802F9F326B842FF2E5F3C00AB7635CF"
+    "B36157FC0882D574A10D839C1A0C049DC5E0D775E2EE50671A208431BB45"
+    "E78E70BEFE930DB34818EE4D5C26259F5C6B8E28A652950F9F88D7B4B2C9"
+    "D9");
+
+struct RSA_Delete {
+    void operator()(RSA* p) { RSA_free(p); }
+};
+
+X509* parse_cert_blob(const hidl_vec<uint8_t>& blob) {
+    const uint8_t* p = blob.data();
+    return d2i_X509(nullptr, &p, blob.size());
+}
+
+bool verify_chain(const hidl_vec<hidl_vec<uint8_t>>& chain) {
+    for (size_t i = 0; i < chain.size() - 1; ++i) {
+        X509_Ptr key_cert(parse_cert_blob(chain[i]));
+        X509_Ptr signing_cert;
+        if (i < chain.size() - 1) {
+            signing_cert.reset(parse_cert_blob(chain[i + 1]));
+        } else {
+            signing_cert.reset(parse_cert_blob(chain[i]));
+        }
+        EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get());
+        if (!key_cert.get() || !signing_cert.get()) return false;
+
+        EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+        EXPECT_TRUE(!!signing_pubkey.get());
+        if (!signing_pubkey.get()) return false;
+
+        EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
+            << "Verification of certificate " << i << " failed";
+
+        char* cert_issuer =  //
+            X509_NAME_oneline(X509_get_issuer_name(key_cert.get()), nullptr, 0);
+        char* signer_subj =
+            X509_NAME_oneline(X509_get_subject_name(signing_cert.get()), nullptr, 0);
+        EXPECT_STREQ(cert_issuer, signer_subj) << "Cert " << i << " has wrong issuer.";
+        if (i == 0) {
+            char* cert_sub = X509_NAME_oneline(X509_get_subject_name(key_cert.get()), nullptr, 0);
+            EXPECT_STREQ("/CN=Android Keystore Key", cert_sub)
+                << "Cert " << i << " has wrong subject.";
+            free(cert_sub);
+        }
+
+        free(cert_issuer);
+        free(signer_subj);
+
+        if (dump_Attestations) std::cout << bin2hex(chain[i]) << std::endl;
+    }
+
+    return true;
+}
+
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
+    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+    EXPECT_TRUE(!!oid.get());
+    if (!oid.get()) return nullptr;
+
+    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+    EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
+    if (location == -1) return nullptr;
+
+    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+    EXPECT_TRUE(!!attest_rec_ext)
+        << "Found attestation extension but couldn't retrieve it?  Probably a BoringSSL bug.";
+    if (!attest_rec_ext) return nullptr;
+
+    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+    EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
+    return attest_rec;
+}
+
+bool tag_in_list(const KeyParameter& entry) {
+    // Attestations don't contain everything in key authorization lists, so we need to filter
+    // the key lists to produce the lists that we expect to match the attestations.
+    auto tag_list = {
+        Tag::INCLUDE_UNIQUE_ID, Tag::BLOB_USAGE_REQUIREMENTS,
+        Tag::EC_CURVE /* Tag::EC_CURVE will be included by KM2 implementations */,
+    };
+    return std::find(tag_list.begin(), tag_list.end(), entry.tag) != tag_list.end();
+}
+
+AuthorizationSet filter_tags(const AuthorizationSet& set) {
+    AuthorizationSet filtered;
+    std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list);
+    return filtered;
+}
+
+std::string make_string(const uint8_t* data, size_t length) {
+    return std::string(reinterpret_cast<const char*>(data), length);
+}
+
+template <size_t N>
+std::string make_string(const uint8_t (&a)[N]) {
+    return make_string(a, N);
+}
+
+}  // namespace
+
+bool verify_attestation_record(const string& challenge, const string& app_id,
+                               AuthorizationSet expected_sw_enforced,
+                               AuthorizationSet expected_tee_enforced,
+                               const hidl_vec<uint8_t>& attestation_cert) {
+    X509_Ptr cert(parse_cert_blob(attestation_cert));
+    EXPECT_TRUE(!!cert.get());
+    if (!cert.get()) return false;
+
+    ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+    EXPECT_TRUE(!!attest_rec);
+    if (!attest_rec) return false;
+
+    AuthorizationSet att_sw_enforced;
+    AuthorizationSet att_tee_enforced;
+    uint32_t att_attestation_version;
+    uint32_t att_keymaster_version;
+    SecurityLevel att_attestation_security_level;
+    SecurityLevel att_keymaster_security_level;
+    HidlBuf att_challenge;
+    HidlBuf att_unique_id;
+    HidlBuf att_app_id;
+    EXPECT_EQ(ErrorCode::OK,
+              parse_attestation_record(attest_rec->data,                 //
+                                       attest_rec->length,               //
+                                       &att_attestation_version,         //
+                                       &att_attestation_security_level,  //
+                                       &att_keymaster_version,           //
+                                       &att_keymaster_security_level,    //
+                                       &att_challenge,                   //
+                                       &att_sw_enforced,                 //
+                                       &att_tee_enforced,                //
+                                       &att_unique_id));
+
+    EXPECT_TRUE(att_attestation_version == 1 || att_attestation_version == 2);
+
+    expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID, HidlBuf(app_id));
+
+    EXPECT_GE(att_keymaster_version, 3U);
+    EXPECT_EQ(KeymasterHidlTest::IsSecure() ? SecurityLevel::TRUSTED_ENVIRONMENT
+                                            : SecurityLevel::SOFTWARE,
+              att_keymaster_security_level);
+    EXPECT_EQ(KeymasterHidlTest::IsSecure() ? SecurityLevel::TRUSTED_ENVIRONMENT
+                                            : SecurityLevel::SOFTWARE,
+              att_attestation_security_level);
+
+    EXPECT_EQ(challenge.length(), att_challenge.size());
+    EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
+
+    att_sw_enforced.Sort();
+    expected_sw_enforced.Sort();
+    EXPECT_EQ(filter_tags(expected_sw_enforced), filter_tags(att_sw_enforced));
+
+    att_tee_enforced.Sort();
+    expected_tee_enforced.Sort();
+    EXPECT_EQ(filter_tags(expected_tee_enforced), filter_tags(att_tee_enforced));
+
+    return true;
+}
+
+class NewKeyGenerationTest : public KeymasterHidlTest {
+   protected:
+    void CheckBaseParams(const KeyCharacteristics& keyCharacteristics) {
+        // TODO(swillden): Distinguish which params should be in which auth list.
+
+        AuthorizationSet auths(keyCharacteristics.hardwareEnforced);
+        auths.push_back(AuthorizationSet(keyCharacteristics.softwareEnforced));
+
+        EXPECT_TRUE(auths.Contains(TAG_ORIGIN, KeyOrigin::GENERATED));
+        EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::SIGN));
+        EXPECT_TRUE(auths.Contains(TAG_PURPOSE, KeyPurpose::VERIFY));
+
+        // Verify that App ID, App data and ROT are NOT included.
+        EXPECT_FALSE(auths.Contains(TAG_ROOT_OF_TRUST));
+        EXPECT_FALSE(auths.Contains(TAG_APPLICATION_ID));
+        EXPECT_FALSE(auths.Contains(TAG_APPLICATION_DATA));
+
+        // Check that some unexpected tags/values are NOT present.
+        EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::ENCRYPT));
+        EXPECT_FALSE(auths.Contains(TAG_PURPOSE, KeyPurpose::DECRYPT));
+        EXPECT_FALSE(auths.Contains(TAG_AUTH_TIMEOUT, 301U));
+
+        // Now check that unspecified, defaulted tags are correct.
+        EXPECT_TRUE(auths.Contains(TAG_CREATION_DATETIME));
+
+        EXPECT_TRUE(auths.Contains(TAG_OS_VERSION, os_version()))
+            << "OS version is " << os_version() << " key reported "
+            << auths.GetTagValue(TAG_OS_VERSION);
+        EXPECT_TRUE(auths.Contains(TAG_OS_PATCHLEVEL, os_patch_level()))
+            << "OS patch level is " << os_patch_level() << " key reported "
+            << auths.GetTagValue(TAG_OS_PATCHLEVEL);
+    }
+
+    void CheckCharacteristics(const HidlBuf& key_blob,
+                              const KeyCharacteristics& key_characteristics) {
+        KeyCharacteristics retrieved_chars;
+        ASSERT_EQ(ErrorCode::OK, GetCharacteristics(key_blob, &retrieved_chars));
+        EXPECT_EQ(key_characteristics, retrieved_chars);
+    }
+};
+
+/*
+ * NewKeyGenerationTest.Rsa
+ *
+ * Verifies that keymaster can generate all required RSA key sizes, and that the resulting keys have
+ * correct characteristics.
+ */
+TEST_F(NewKeyGenerationTest, Rsa) {
+    for (uint32_t key_size : {1024, 2048, 3072, 4096}) {
+        HidlBuf key_blob;
+        KeyCharacteristics key_characteristics;
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .RsaSigningKey(key_size, 3)
+                                                 .Digest(Digest::NONE)
+                                                 .Padding(PaddingMode::NONE),
+                                             &key_blob, &key_characteristics));
+
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
+
+        AuthorizationSet crypto_params;
+        if (IsSecure()) {
+            crypto_params = key_characteristics.hardwareEnforced;
+        } else {
+            crypto_params = key_characteristics.softwareEnforced;
+        }
+
+        EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
+        EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+            << "Key size " << key_size << "missing";
+        EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 3U));
+
+        CheckedDeleteKey(&key_blob);
+    }
+}
+
+/*
+ * NewKeyGenerationTest.RsaNoDefaultSize
+ *
+ * Verifies that failing to specify a key size for RSA key generation returns UNSUPPORTED_KEY_SIZE.
+ */
+TEST_F(NewKeyGenerationTest, RsaNoDefaultSize) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder()
+                              .Authorization(TAG_ALGORITHM, Algorithm::RSA)
+                              .Authorization(TAG_RSA_PUBLIC_EXPONENT, 3U)
+                              .SigningKey()));
+}
+
+/*
+ * NewKeyGenerationTest.Ecdsa
+ *
+ * Verifies that keymaster can generate all required EC key sizes, and that the resulting keys have
+ * correct characteristics.
+ */
+TEST_F(NewKeyGenerationTest, Ecdsa) {
+    for (uint32_t key_size : {224, 256, 384, 521}) {
+        HidlBuf key_blob;
+        KeyCharacteristics key_characteristics;
+        ASSERT_EQ(
+            ErrorCode::OK,
+            GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(key_size).Digest(Digest::NONE),
+                        &key_blob, &key_characteristics));
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
+
+        AuthorizationSet crypto_params;
+        if (IsSecure()) {
+            crypto_params = key_characteristics.hardwareEnforced;
+        } else {
+            crypto_params = key_characteristics.softwareEnforced;
+        }
+
+        EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::EC));
+        EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+            << "Key size " << key_size << "missing";
+
+        CheckedDeleteKey(&key_blob);
+    }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaDefaultSize
+ *
+ * Verifies that failing to specify a key size for EC key generation returns UNSUPPORTED_KEY_SIZE.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaDefaultSize) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder()
+                              .Authorization(TAG_ALGORITHM, Algorithm::EC)
+                              .SigningKey()
+                              .Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaInvalidSize
+ *
+ * Verifies that failing to specify an invalid key size for EC key generation returns
+ * UNSUPPORTED_KEY_SIZE.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaInvalidSize) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+              GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(190).Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaMismatchKeySize
+ *
+ * Verifies that specifying mismatched key size and curve for EC key generation returns
+ * INVALID_ARGUMENT.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaMismatchKeySize) {
+    ASSERT_EQ(ErrorCode::INVALID_ARGUMENT,
+              GenerateKey(AuthorizationSetBuilder()
+                              .EcdsaSigningKey(224)
+                              .Authorization(TAG_EC_CURVE, EcCurve::P_256)
+                              .Digest(Digest::NONE)));
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaAllValidSizes
+ *
+ * Verifies that keymaster supports all required EC key sizes.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaAllValidSizes) {
+    size_t valid_sizes[] = {224, 256, 384, 521};
+    for (size_t size : valid_sizes) {
+        EXPECT_EQ(ErrorCode::OK,
+                  GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(size).Digest(Digest::NONE)))
+            << "Failed to generate size: " << size;
+        CheckCharacteristics(key_blob_, key_characteristics_);
+        CheckedDeleteKey();
+    }
+}
+
+/*
+ * NewKeyGenerationTest.EcdsaAllValidCurves
+ *
+ * Verifies that keymaster supports all required EC curves.
+ */
+TEST_F(NewKeyGenerationTest, EcdsaAllValidCurves) {
+    V4_0::EcCurve curves[] = {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521};
+    for (V4_0::EcCurve curve : curves) {
+        EXPECT_EQ(
+            ErrorCode::OK,
+            GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(curve).Digest(Digest::SHA_2_512)))
+            << "Failed to generate key on curve: " << curve;
+        CheckCharacteristics(key_blob_, key_characteristics_);
+        CheckedDeleteKey();
+    }
+}
+
+/*
+ * NewKeyGenerationTest.Hmac
+ *
+ * Verifies that keymaster supports all required digests, and that the resulting keys have correct
+ * characteristics.
+ */
+TEST_F(NewKeyGenerationTest, Hmac) {
+    for (auto digest : {Digest::MD5, Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256,
+                        Digest::SHA_2_384, Digest::SHA_2_512}) {
+        HidlBuf key_blob;
+        KeyCharacteristics key_characteristics;
+        constexpr size_t key_size = 128;
+        ASSERT_EQ(
+            ErrorCode::OK,
+            GenerateKey(AuthorizationSetBuilder().HmacKey(key_size).Digest(digest).Authorization(
+                            TAG_MIN_MAC_LENGTH, 128),
+                        &key_blob, &key_characteristics));
+
+        ASSERT_GT(key_blob.size(), 0U);
+        CheckBaseParams(key_characteristics);
+        CheckCharacteristics(key_blob, key_characteristics);
+
+        AuthorizationSet hardwareEnforced = key_characteristics.hardwareEnforced;
+        AuthorizationSet softwareEnforced = key_characteristics.softwareEnforced;
+        if (IsSecure()) {
+            EXPECT_TRUE(hardwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+            EXPECT_TRUE(hardwareEnforced.Contains(TAG_KEY_SIZE, key_size))
+                << "Key size " << key_size << "missing";
+        } else {
+            EXPECT_TRUE(softwareEnforced.Contains(TAG_ALGORITHM, Algorithm::HMAC));
+            EXPECT_TRUE(softwareEnforced.Contains(TAG_KEY_SIZE, key_size))
+                << "Key size " << key_size << "missing";
+        }
+
+        CheckedDeleteKey(&key_blob);
+    }
+}
+
+/*
+ * NewKeyGenerationTest.HmacCheckKeySizes
+ *
+ * Verifies that keymaster supports all key sizes, and rejects all invalid key sizes.
+ */
+TEST_F(NewKeyGenerationTest, HmacCheckKeySizes) {
+    for (size_t key_size = 0; key_size <= 512; ++key_size) {
+        if (key_size < 64 || key_size % 8 != 0) {
+            // To keep this test from being very slow, we only test a random fraction of non-byte
+            // key sizes.  We test only ~10% of such cases. Since there are 392 of them, we expect
+            // to run ~40 of them in each run.
+            if (key_size % 8 == 0 || random() % 10 == 0) {
+                EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_SIZE,
+                          GenerateKey(AuthorizationSetBuilder()
+                                          .HmacKey(key_size)
+                                          .Digest(Digest::SHA_2_256)
+                                          .Authorization(TAG_MIN_MAC_LENGTH, 256)))
+                    << "HMAC key size " << key_size << " invalid";
+            }
+        } else {
+            EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                     .HmacKey(key_size)
+                                                     .Digest(Digest::SHA_2_256)
+                                                     .Authorization(TAG_MIN_MAC_LENGTH, 256)))
+                << "Failed to generate HMAC key of size " << key_size;
+            CheckCharacteristics(key_blob_, key_characteristics_);
+            CheckedDeleteKey();
+        }
+    }
+}
+
+/*
+ * NewKeyGenerationTest.HmacCheckMinMacLengths
+ *
+ * Verifies that keymaster supports all required MAC lengths and rejects all invalid lengths.  This
+ * test is probabilistic in order to keep the runtime down, but any failure prints out the specific
+ * MAC length that failed, so reproducing a failed run will be easy.
+ */
+TEST_F(NewKeyGenerationTest, HmacCheckMinMacLengths) {
+    for (size_t min_mac_length = 0; min_mac_length <= 256; ++min_mac_length) {
+        if (min_mac_length < 64 || min_mac_length % 8 != 0) {
+            // To keep this test from being very long, we only test a random fraction of non-byte
+            // lengths.  We test only ~10% of such cases. Since there are 172 of them, we expect to
+            // run ~17 of them in each run.
+            if (min_mac_length % 8 == 0 || random() % 10 == 0) {
+                EXPECT_EQ(ErrorCode::UNSUPPORTED_MIN_MAC_LENGTH,
+                          GenerateKey(AuthorizationSetBuilder()
+                                          .HmacKey(128)
+                                          .Digest(Digest::SHA_2_256)
+                                          .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length)))
+                    << "HMAC min mac length " << min_mac_length << " invalid.";
+            }
+        } else {
+            EXPECT_EQ(ErrorCode::OK,
+                      GenerateKey(AuthorizationSetBuilder()
+                                      .HmacKey(128)
+                                      .Digest(Digest::SHA_2_256)
+                                      .Authorization(TAG_MIN_MAC_LENGTH, min_mac_length)))
+                << "Failed to generate HMAC key with min MAC length " << min_mac_length;
+            CheckCharacteristics(key_blob_, key_characteristics_);
+            CheckedDeleteKey();
+        }
+    }
+}
+
+/*
+ * NewKeyGenerationTest.HmacMultipleDigests
+ *
+ * Verifies that keymaster rejects HMAC key generation with multiple specified digest algorithms.
+ */
+TEST_F(NewKeyGenerationTest, HmacMultipleDigests) {
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+              GenerateKey(AuthorizationSetBuilder()
+                              .HmacKey(128)
+                              .Digest(Digest::SHA1)
+                              .Digest(Digest::SHA_2_256)
+                              .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+}
+
+/*
+ * NewKeyGenerationTest.HmacDigestNone
+ *
+ * Verifies that keymaster rejects HMAC key generation with no digest or Digest::NONE
+ */
+TEST_F(NewKeyGenerationTest, HmacDigestNone) {
+    ASSERT_EQ(
+        ErrorCode::UNSUPPORTED_DIGEST,
+        GenerateKey(AuthorizationSetBuilder().HmacKey(128).Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+              GenerateKey(AuthorizationSetBuilder()
+                              .HmacKey(128)
+                              .Digest(Digest::NONE)
+                              .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+}
+
+typedef KeymasterHidlTest SigningOperationsTest;
+
+/*
+ * SigningOperationsTest.RsaSuccess
+ *
+ * Verifies that raw RSA signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+    string message = "12345678901234567890123456789012";
+    string signature = SignMessage(
+        message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * SigningOperationsTest.RsaPssSha256Success
+ *
+ * Verifies that RSA-PSS signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaPssSha256Success) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Padding(PaddingMode::RSA_PSS)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+    // Use large message, which won't work without digesting.
+    string message(1024, 'a');
+    string signature = SignMessage(
+        message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS));
+}
+
+/*
+ * SigningOperationsTest.RsaPaddingNoneDoesNotAllowOther
+ *
+ * Verifies that keymaster rejects signature operations that specify a padding mode when the key
+ * supports only unpadded operations.
+ */
+TEST_F(SigningOperationsTest, RsaPaddingNoneDoesNotAllowOther) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature;
+
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                          .Digest(Digest::NONE)
+                                          .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+}
+
+/*
+ * SigningOperationsTest.NoUserConfirmation
+ *
+ * Verifies that keymaster rejects signing operations for keys with
+ * TRUSTED_CONFIRMATION_REQUIRED and no valid confirmation token
+ * presented.
+ */
+TEST_F(SigningOperationsTest, NoUserConfirmation) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Authorization(TAG_TRUSTED_CONFIRMATION_REQUIRED)));
+
+    const string message = "12345678901234567890123456789012";
+    EXPECT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+    string signature;
+    EXPECT_EQ(ErrorCode::NO_USER_CONFIRMATION, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1Sha256Success
+ *
+ * Verifies that digested RSA-PKCS1 signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaPkcs1Sha256Success) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string message(1024, 'a');
+    string signature = SignMessage(message, AuthorizationSetBuilder()
+                                                .Digest(Digest::SHA_2_256)
+                                                .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1NoDigestSuccess
+ *
+ * Verifies that undigested RSA-PKCS1 signature operations succeed.
+ */
+TEST_F(SigningOperationsTest, RsaPkcs1NoDigestSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string message(53, 'a');
+    string signature = SignMessage(
+        message,
+        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::RSA_PKCS1_1_5_SIGN));
+}
+
+/*
+ * SigningOperationsTest.RsaPkcs1NoDigestTooLarge
+ *
+ * Verifies that undigested RSA-PKCS1 signature operations fail with the correct error code when
+ * given a too-long message.
+ */
+TEST_F(SigningOperationsTest, RsaPkcs1NoDigestTooLong) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string message(129, 'a');
+
+    EXPECT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                          .Digest(Digest::NONE)
+                                          .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string signature;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.RsaPssSha512TooSmallKey
+ *
+ * Verifies that undigested RSA-PSS signature operations fail with the correct error code when
+ * used with a key that is too small for the message.
+ *
+ * A PSS-padded message is of length salt_size + digest_size + 16 (sizes in bits), and the keymaster
+ * specification requires that salt_size == digest_size, so the message will be digest_size * 2 +
+ * 16. Such a message can only be signed by a given key if the key is at least that size. This test
+ * uses SHA512, which has a digest_size == 512, so the message size is 1040 bits, too large for a
+ * 1024-bit key.
+ */
+TEST_F(SigningOperationsTest, RsaPssSha512TooSmallKey) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::SHA_2_512)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::RSA_PSS)));
+    EXPECT_EQ(
+        ErrorCode::INCOMPATIBLE_DIGEST,
+        Begin(KeyPurpose::SIGN,
+              AuthorizationSetBuilder().Digest(Digest::SHA_2_512).Padding(PaddingMode::RSA_PSS)));
+}
+
+/*
+ * SigningOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA signature operations fail with the correct error code when
+ * given a too-long message.
+ */
+TEST_F(SigningOperationsTest, RsaNoPaddingTooLong) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    // One byte too long
+    string message(1024 / 8 + 1, 'a');
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                          .Digest(Digest::NONE)
+                                          .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    string result;
+    ErrorCode finish_error_code = Finish(message, &result);
+    EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH ||
+                finish_error_code == ErrorCode::INVALID_ARGUMENT);
+
+    // Very large message that should exceed the transfer buffer size of any reasonable TEE.
+    message = string(128 * 1024, 'a');
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                          .Digest(Digest::NONE)
+                                          .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+    finish_error_code = Finish(message, &result);
+    EXPECT_TRUE(finish_error_code == ErrorCode::INVALID_INPUT_LENGTH ||
+                finish_error_code == ErrorCode::INVALID_ARGUMENT);
+}
+
+/*
+ * SigningOperationsTest.RsaAbort
+ *
+ * Verifies that operations can be aborted correctly.  Uses an RSA signing operation for the test,
+ * but the behavior should be algorithm and purpose-independent.
+ */
+TEST_F(SigningOperationsTest, RsaAbort) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Padding(PaddingMode::NONE)));
+
+    ASSERT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+    EXPECT_EQ(ErrorCode::OK, Abort(op_handle_));
+
+    // Another abort should fail
+    EXPECT_EQ(ErrorCode::INVALID_OPERATION_HANDLE, Abort(op_handle_));
+
+    // Set to sentinel, so TearDown() doesn't try to abort again.
+    op_handle_ = kOpHandleSentinel;
+}
+
+/*
+ * SigningOperationsTest.RsaUnsupportedPadding
+ *
+ * Verifies that RSA operations fail with the correct error (but key gen succeeds) when used with a
+ * padding mode inappropriate for RSA.
+ */
+TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Digest(Digest::SHA_2_256 /* supported digest */)
+                                             .Padding(PaddingMode::PKCS7)));
+    ASSERT_EQ(
+        ErrorCode::UNSUPPORTED_PADDING_MODE,
+        Begin(KeyPurpose::SIGN,
+              AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::PKCS7)));
+}
+
+/*
+ * SigningOperationsTest.RsaPssNoDigest
+ *
+ * Verifies that RSA PSS operations fail when no digest is used.  PSS requires a digest.
+ */
+TEST_F(SigningOperationsTest, RsaNoDigest) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::RSA_PSS)));
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_DIGEST,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::RSA_PSS)));
+
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Padding(PaddingMode::RSA_PSS)));
+}
+
+/*
+ * SigningOperationsTest.RsaPssNoDigest
+ *
+ * Verifies that RSA operations fail when no padding mode is specified.  PaddingMode::NONE is
+ * supported in some cases (as validated in other tests), but a mode must be specified.
+ */
+TEST_F(SigningOperationsTest, RsaNoPadding) {
+    // Padding must be specified
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaKey(1024, 3)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .SigningKey()
+                                             .Digest(Digest::NONE)));
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PADDING_MODE,
+              Begin(KeyPurpose::SIGN, AuthorizationSetBuilder().Digest(Digest::NONE)));
+}
+
+/*
+ * SigningOperationsTest.RsaShortMessage
+ *
+ * Verifies that raw RSA signatures succeed with a message shorter than the key size.
+ */
+TEST_F(SigningOperationsTest, RsaTooShortMessage) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+
+    // Barely shorter
+    string message(1024 / 8 - 1, 'a');
+    SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+
+    // Much shorter
+    message = "a";
+    SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * SigningOperationsTest.RsaSignWithEncryptionKey
+ *
+ * Verifies that RSA encryption keys cannot be used to sign.
+ */
+TEST_F(SigningOperationsTest, RsaSignWithEncryptionKey) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              Begin(KeyPurpose::SIGN,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE)));
+}
+
+/*
+ * SigningOperationsTest.RsaSignTooLargeMessage
+ *
+ * Verifies that attempting a raw signature of a message which is the same length as the key, but
+ * numerically larger than the public modulus, fails with the correct error.
+ */
+TEST_F(SigningOperationsTest, RsaSignTooLargeMessage) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+
+    // Largest possible message will always be larger than the public modulus.
+    string message(1024 / 8, static_cast<char>(0xff));
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, AuthorizationSetBuilder()
+                                                         .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                         .Digest(Digest::NONE)
+                                                         .Padding(PaddingMode::NONE)));
+    string signature;
+    ASSERT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &signature));
+}
+
+/*
+ * SigningOperationsTest.EcdsaAllSizesAndHashes
+ *
+ * Verifies that ECDSA operations succeed with all possible key sizes and hashes.
+ */
+TEST_F(SigningOperationsTest, EcdsaAllSizesAndHashes) {
+    for (auto key_size : {224, 256, 384, 521}) {
+        for (auto digest : {
+                 Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
+                 Digest::SHA_2_512,
+             }) {
+            ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                              .Authorization(TAG_NO_AUTH_REQUIRED)
+                                              .EcdsaSigningKey(key_size)
+                                              .Digest(digest));
+            EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with size " << key_size
+                                            << " and digest " << digest;
+            if (error != ErrorCode::OK) continue;
+
+            string message(1024, 'a');
+            if (digest == Digest::NONE) message.resize(key_size / 8);
+            SignMessage(message, AuthorizationSetBuilder().Digest(digest));
+            CheckedDeleteKey();
+        }
+    }
+}
+
+/*
+ * SigningOperationsTest.EcdsaAllCurves
+ *
+ * Verifies that ECDSA operations succeed with all possible curves.
+ */
+TEST_F(SigningOperationsTest, EcdsaAllCurves) {
+    for (auto curve : {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521}) {
+        ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .EcdsaSigningKey(curve)
+                                          .Digest(Digest::SHA_2_256));
+        EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate ECDSA key with curve " << curve;
+        if (error != ErrorCode::OK) continue;
+
+        string message(1024, 'a');
+        SignMessage(message, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+        CheckedDeleteKey();
+    }
+}
+
+/*
+ * SigningOperationsTest.EcdsaNoDigestHugeData
+ *
+ * Verifies that ECDSA operations support very large messages, even without digesting.  This should
+ * work because ECDSA actually only signs the leftmost L_n bits of the message, however large it may
+ * be.  Not using digesting is a bad idea, but in some cases digesting is done by the framework.
+ */
+TEST_F(SigningOperationsTest, EcdsaNoDigestHugeData) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(224)
+                                             .Digest(Digest::NONE)));
+    string message(2 * 1024, 'a');
+    SignMessage(message, AuthorizationSetBuilder().Digest(Digest::NONE));
+}
+
+/*
+ * SigningOperationsTest.AesEcbSign
+ *
+ * Verifies that attempts to use AES keys to sign fail in the correct way.
+ */
+TEST_F(SigningOperationsTest, AesEcbSign) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .SigningKey()
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)));
+
+    AuthorizationSet out_params;
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE,
+              Begin(KeyPurpose::SIGN, AuthorizationSet() /* in_params */, &out_params));
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_PURPOSE,
+              Begin(KeyPurpose::VERIFY, AuthorizationSet() /* in_params */, &out_params));
+}
+
+/*
+ * SigningOperationsTest.HmacAllDigests
+ *
+ * Verifies that HMAC works with all digests.
+ */
+TEST_F(SigningOperationsTest, HmacAllDigests) {
+    for (auto digest : {Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_256, Digest::SHA_2_384,
+                        Digest::SHA_2_512}) {
+        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .HmacKey(128)
+                                                 .Digest(digest)
+                                                 .Authorization(TAG_MIN_MAC_LENGTH, 160)))
+            << "Failed to create HMAC key with digest " << digest;
+        string message = "12345678901234567890123456789012";
+        string signature = MacMessage(message, digest, 160);
+        EXPECT_EQ(160U / 8U, signature.size())
+            << "Failed to sign with HMAC key with digest " << digest;
+        CheckedDeleteKey();
+    }
+}
+
+/*
+ * SigningOperationsTest.HmacSha256TooLargeMacLength
+ *
+ * Verifies that HMAC fails in the correct way when asked to generate a MAC larger than the digest
+ * size.
+ */
+TEST_F(SigningOperationsTest, HmacSha256TooLargeMacLength) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .HmacKey(128)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 256)));
+    AuthorizationSet output_params;
+    EXPECT_EQ(
+        ErrorCode::UNSUPPORTED_MAC_LENGTH,
+        Begin(
+            KeyPurpose::SIGN, key_blob_,
+            AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Authorization(TAG_MAC_LENGTH, 264),
+            &output_params, &op_handle_));
+}
+
+/*
+ * SigningOperationsTest.HmacSha256TooSmallMacLength
+ *
+ * Verifies that HMAC fails in the correct way when asked to generate a MAC smaller than the
+ * specified minimum MAC length.
+ */
+TEST_F(SigningOperationsTest, HmacSha256TooSmallMacLength) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .HmacKey(128)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    AuthorizationSet output_params;
+    EXPECT_EQ(
+        ErrorCode::INVALID_MAC_LENGTH,
+        Begin(
+            KeyPurpose::SIGN, key_blob_,
+            AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Authorization(TAG_MAC_LENGTH, 120),
+            &output_params, &op_handle_));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase3
+ *
+ * Validates against the test vectors from RFC 4231 test case 3.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase3) {
+    string key(20, 0xaa);
+    string message(50, 0xdd);
+    uint8_t sha_224_expected[] = {
+        0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6, 0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a,
+        0xd2, 0x64, 0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1, 0xec, 0x83, 0x33, 0xea,
+    };
+    uint8_t sha_256_expected[] = {
+        0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8,
+        0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8,
+        0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe,
+    };
+    uint8_t sha_384_expected[] = {
+        0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a, 0x0a, 0xa2, 0xac, 0xe0,
+        0x14, 0xc8, 0xa8, 0x6f, 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+        0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b, 0x2a, 0x5a, 0xb3, 0x9d,
+        0xc1, 0x38, 0x14, 0xb9, 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27,
+    };
+    uint8_t sha_512_expected[] = {
+        0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c,
+        0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8,
+        0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22,
+        0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37,
+        0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb,
+    };
+
+    CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase5
+ *
+ * Validates against the test vectors from RFC 4231 test case 5.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase5) {
+    string key(20, 0x0c);
+    string message = "Test With Truncation";
+
+    uint8_t sha_224_expected[] = {
+        0x0e, 0x2a, 0xea, 0x68, 0xa9, 0x0c, 0x8d, 0x37,
+        0xc9, 0x88, 0xbc, 0xdb, 0x9f, 0xca, 0x6f, 0xa8,
+    };
+    uint8_t sha_256_expected[] = {
+        0xa3, 0xb6, 0x16, 0x74, 0x73, 0x10, 0x0e, 0xe0,
+        0x6e, 0x0c, 0x79, 0x6c, 0x29, 0x55, 0x55, 0x2b,
+    };
+    uint8_t sha_384_expected[] = {
+        0x3a, 0xbf, 0x34, 0xc3, 0x50, 0x3b, 0x2a, 0x23,
+        0xa4, 0x6e, 0xfc, 0x61, 0x9b, 0xae, 0xf8, 0x97,
+    };
+    uint8_t sha_512_expected[] = {
+        0x41, 0x5f, 0xad, 0x62, 0x71, 0x58, 0x0a, 0x53,
+        0x1d, 0x41, 0x79, 0xbc, 0x89, 0x1d, 0x87, 0xa6,
+    };
+
+    CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase6
+ *
+ * Validates against the test vectors from RFC 4231 test case 6.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase6) {
+    string key(131, 0xaa);
+    string message = "Test Using Larger Than Block-Size Key - Hash Key First";
+
+    uint8_t sha_224_expected[] = {
+        0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad, 0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d,
+        0xbc, 0xe2, 0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27, 0x3f, 0xa6, 0x87, 0x0e,
+    };
+    uint8_t sha_256_expected[] = {
+        0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26,
+        0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28,
+        0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54,
+    };
+    uint8_t sha_384_expected[] = {
+        0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90, 0x88, 0xd2, 0xc6, 0x3a,
+        0x04, 0x1b, 0xc5, 0xb4, 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+        0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6, 0x0c, 0x2e, 0xf6, 0xab,
+        0x40, 0x30, 0xfe, 0x82, 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52,
+    };
+    uint8_t sha_512_expected[] = {
+        0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1, 0xdd,
+        0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, 0x12, 0x1b,
+        0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25,
+        0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, 0x95, 0xe6, 0x4f, 0x73,
+        0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98,
+    };
+
+    CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+/*
+ * SigningOperationsTest.HmacRfc4231TestCase7
+ *
+ * Validates against the test vectors from RFC 4231 test case 7.
+ */
+TEST_F(SigningOperationsTest, HmacRfc4231TestCase7) {
+    string key(131, 0xaa);
+    string message =
+        "This is a test using a larger than block-size key and a larger than "
+        "block-size data. The key needs to be hashed before being used by the HMAC "
+        "algorithm.";
+
+    uint8_t sha_224_expected[] = {
+        0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02, 0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3,
+        0x9d, 0xbd, 0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9, 0xf6, 0xf5, 0x65, 0xd1,
+    };
+    uint8_t sha_256_expected[] = {
+        0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f,
+        0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07,
+        0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2,
+    };
+    uint8_t sha_384_expected[] = {
+        0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d, 0x35, 0x1e, 0x2f, 0x25,
+        0x4e, 0x8f, 0xd3, 0x2c, 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+        0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5, 0xa6, 0x78, 0xcc, 0x31,
+        0xe7, 0x99, 0x17, 0x6d, 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e,
+    };
+    uint8_t sha_512_expected[] = {
+        0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba, 0xa4, 0xdf, 0xa9, 0xf9, 0x6e,
+        0x5e, 0x3f, 0xfd, 0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86, 0x5d, 0xf5,
+        0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44, 0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82,
+        0xb1, 0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15, 0x13, 0x46, 0x76, 0xfb,
+        0x6d, 0xe0, 0x44, 0x60, 0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58,
+    };
+
+    CheckHmacTestVector(key, message, Digest::SHA_2_224, make_string(sha_224_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_256, make_string(sha_256_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_384, make_string(sha_384_expected));
+    CheckHmacTestVector(key, message, Digest::SHA_2_512, make_string(sha_512_expected));
+}
+
+typedef KeymasterHidlTest VerificationOperationsTest;
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies that a simple RSA signature/verification sequence succeeds.
+ */
+TEST_F(VerificationOperationsTest, RsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+    string message = "12345678901234567890123456789012";
+    string signature = SignMessage(
+        message, AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+    VerifyMessage(message, signature,
+                  AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE));
+}
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies RSA signature/verification for all padding modes and digests.
+ */
+TEST_F(VerificationOperationsTest, RsaAllPaddingsAndDigests) {
+    ASSERT_EQ(ErrorCode::OK,
+              GenerateKey(AuthorizationSetBuilder()
+                              .Authorization(TAG_NO_AUTH_REQUIRED)
+                              .RsaSigningKey(2048, 3)
+                              .Digest(Digest::NONE, Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+                                      Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512)
+                              .Padding(PaddingMode::NONE)
+                              .Padding(PaddingMode::RSA_PSS)
+                              .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)));
+
+    string message(128, 'a');
+    string corrupt_message(message);
+    ++corrupt_message[corrupt_message.size() / 2];
+
+    for (auto padding :
+         {PaddingMode::NONE, PaddingMode::RSA_PSS, PaddingMode::RSA_PKCS1_1_5_SIGN}) {
+        for (auto digest : {Digest::NONE, Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+                            Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512}) {
+            if (padding == PaddingMode::NONE && digest != Digest::NONE) {
+                // Digesting only makes sense with padding.
+                continue;
+            }
+
+            if (padding == PaddingMode::RSA_PSS && digest == Digest::NONE) {
+                // PSS requires digesting.
+                continue;
+            }
+
+            string signature =
+                SignMessage(message, AuthorizationSetBuilder().Digest(digest).Padding(padding));
+            VerifyMessage(message, signature,
+                          AuthorizationSetBuilder().Digest(digest).Padding(padding));
+
+            if (digest != Digest::NONE) {
+                // Verify with OpenSSL.
+                HidlBuf pubkey;
+                ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey));
+
+                const uint8_t* p = pubkey.data();
+                EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
+                ASSERT_TRUE(pkey.get());
+
+                EVP_MD_CTX digest_ctx;
+                EVP_MD_CTX_init(&digest_ctx);
+                EVP_PKEY_CTX* pkey_ctx;
+                const EVP_MD* md = openssl_digest(digest);
+                ASSERT_NE(md, nullptr);
+                EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md, nullptr /* engine */,
+                                                  pkey.get()));
+
+                switch (padding) {
+                    case PaddingMode::RSA_PSS:
+                        EXPECT_GT(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING), 0);
+                        EXPECT_GT(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, EVP_MD_size(md)), 0);
+                        break;
+                    case PaddingMode::RSA_PKCS1_1_5_SIGN:
+                        // PKCS1 is the default; don't need to set anything.
+                        break;
+                    default:
+                        FAIL();
+                        break;
+                }
+
+                EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()));
+                EXPECT_EQ(1, EVP_DigestVerifyFinal(
+                                 &digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
+                                 signature.size()));
+                EVP_MD_CTX_cleanup(&digest_ctx);
+            }
+
+            // Corrupt signature shouldn't verify.
+            string corrupt_signature(signature);
+            ++corrupt_signature[corrupt_signature.size() / 2];
+
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY,
+                            AuthorizationSetBuilder().Digest(digest).Padding(padding)));
+            string result;
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result));
+
+            // Corrupt message shouldn't verify
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY,
+                            AuthorizationSetBuilder().Digest(digest).Padding(padding)));
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result));
+        }
+    }
+}
+
+/*
+ * VerificationOperationsTest.RsaSuccess
+ *
+ * Verifies ECDSA signature/verification for all digests and curves.
+ */
+TEST_F(VerificationOperationsTest, EcdsaAllDigestsAndCurves) {
+    auto digests = {
+        Digest::NONE,      Digest::SHA1,      Digest::SHA_2_224,
+        Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512,
+    };
+
+    string message = "1234567890";
+    string corrupt_message = "2234567890";
+    for (auto curve : {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521}) {
+        ErrorCode error = GenerateKey(AuthorizationSetBuilder()
+                                          .Authorization(TAG_NO_AUTH_REQUIRED)
+                                          .EcdsaSigningKey(curve)
+                                          .Digest(digests));
+        EXPECT_EQ(ErrorCode::OK, error) << "Failed to generate key for EC curve " << curve;
+        if (error != ErrorCode::OK) {
+            continue;
+        }
+
+        for (auto digest : digests) {
+            string signature = SignMessage(message, AuthorizationSetBuilder().Digest(digest));
+            VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(digest));
+
+            // Verify with OpenSSL
+            if (digest != Digest::NONE) {
+                HidlBuf pubkey;
+                ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &pubkey))
+                    << curve << ' ' << digest;
+
+                const uint8_t* p = pubkey.data();
+                EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, pubkey.size()));
+                ASSERT_TRUE(pkey.get());
+
+                EVP_MD_CTX digest_ctx;
+                EVP_MD_CTX_init(&digest_ctx);
+                EVP_PKEY_CTX* pkey_ctx;
+                const EVP_MD* md = openssl_digest(digest);
+
+                EXPECT_EQ(1, EVP_DigestVerifyInit(&digest_ctx, &pkey_ctx, md, nullptr /* engine */,
+                                                  pkey.get()))
+                    << curve << ' ' << digest;
+
+                EXPECT_EQ(1, EVP_DigestVerifyUpdate(&digest_ctx, message.data(), message.size()))
+                    << curve << ' ' << digest;
+
+                EXPECT_EQ(1, EVP_DigestVerifyFinal(
+                                 &digest_ctx, reinterpret_cast<const uint8_t*>(signature.data()),
+                                 signature.size()))
+                    << curve << ' ' << digest;
+
+                EVP_MD_CTX_cleanup(&digest_ctx);
+            }
+
+            // Corrupt signature shouldn't verify.
+            string corrupt_signature(signature);
+            ++corrupt_signature[corrupt_signature.size() / 2];
+
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest)))
+                << curve << ' ' << digest;
+
+            string result;
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(message, corrupt_signature, &result))
+                << curve << ' ' << digest;
+
+            // Corrupt message shouldn't verify
+            EXPECT_EQ(ErrorCode::OK,
+                      Begin(KeyPurpose::VERIFY, AuthorizationSetBuilder().Digest(digest)))
+                << curve << ' ' << digest;
+
+            EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(corrupt_message, signature, &result))
+                << curve << ' ' << digest;
+        }
+
+        auto rc = DeleteKey();
+        ASSERT_TRUE(rc == ErrorCode::OK || rc == ErrorCode::UNIMPLEMENTED);
+    }
+}
+
+/*
+ * VerificationOperationsTest.HmacSigningKeyCannotVerify
+ *
+ * Verifies HMAC signing and verification, but that a signing key cannot be used to verify.
+ */
+TEST_F(VerificationOperationsTest, HmacSigningKeyCannotVerify) {
+    string key_material = "HelloThisIsAKey";
+
+    HidlBuf signing_key, verification_key;
+    KeyCharacteristics signing_key_chars, verification_key_chars;
+    EXPECT_EQ(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+                            .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+                            .Digest(Digest::SHA1)
+                            .Authorization(TAG_MIN_MAC_LENGTH, 160),
+                        KeyFormat::RAW, key_material, &signing_key, &signing_key_chars));
+    EXPECT_EQ(ErrorCode::OK,
+              ImportKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_NO_AUTH_REQUIRED)
+                            .Authorization(TAG_ALGORITHM, Algorithm::HMAC)
+                            .Authorization(TAG_PURPOSE, KeyPurpose::VERIFY)
+                            .Digest(Digest::SHA1)
+                            .Authorization(TAG_MIN_MAC_LENGTH, 160),
+                        KeyFormat::RAW, key_material, &verification_key, &verification_key_chars));
+
+    string message = "This is a message.";
+    string signature = SignMessage(
+        signing_key, message,
+        AuthorizationSetBuilder().Digest(Digest::SHA1).Authorization(TAG_MAC_LENGTH, 160));
+
+    // Signing key should not work.
+    AuthorizationSet out_params;
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              Begin(KeyPurpose::VERIFY, signing_key, AuthorizationSetBuilder().Digest(Digest::SHA1),
+                    &out_params, &op_handle_));
+
+    // Verification key should work.
+    VerifyMessage(verification_key, message, signature,
+                  AuthorizationSetBuilder().Digest(Digest::SHA1));
+
+    CheckedDeleteKey(&signing_key);
+    CheckedDeleteKey(&verification_key);
+}
+
+typedef KeymasterHidlTest ExportKeyTest;
+
+/*
+ * ExportKeyTest.RsaUnsupportedKeyFormat
+ *
+ * Verifies that attempting to export RSA keys in PKCS#8 format fails with the correct error.
+ */
+TEST_F(ExportKeyTest, RsaUnsupportedKeyFormat) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+    HidlBuf export_data;
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::PKCS8, &export_data));
+}
+
+/*
+ * ExportKeyTest.RsaCorruptedKeyBlob
+ *
+ * Verifies that attempting to export RSA keys from corrupted key blobs fails.  This is essentially
+ * a poor-man's key blob fuzzer.
+ */
+TEST_F(ExportKeyTest, RsaCorruptedKeyBlob) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)));
+    for (size_t i = 0; i < key_blob_.size(); ++i) {
+        HidlBuf corrupted(key_blob_);
+        ++corrupted[i];
+
+        HidlBuf export_data;
+        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+                  ExportKey(KeyFormat::X509, corrupted, HidlBuf(), HidlBuf(), &export_data))
+            << "Blob corrupted at offset " << i << " erroneously accepted as valid";
+    }
+}
+
+/*
+ * ExportKeyTest.RsaCorruptedKeyBlob
+ *
+ * Verifies that attempting to export ECDSA keys from corrupted key blobs fails.  This is
+ * essentially a poor-man's key blob fuzzer.
+ */
+TEST_F(ExportKeyTest, EcCorruptedKeyBlob) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(EcCurve::P_256)
+                                             .Digest(Digest::NONE)));
+    for (size_t i = 0; i < key_blob_.size(); ++i) {
+        HidlBuf corrupted(key_blob_);
+        ++corrupted[i];
+
+        HidlBuf export_data;
+        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+                  ExportKey(KeyFormat::X509, corrupted, HidlBuf(), HidlBuf(), &export_data))
+            << "Blob corrupted at offset " << i << " erroneously accepted as valid";
+    }
+}
+
+/*
+ * ExportKeyTest.AesKeyUnexportable
+ *
+ * Verifies that attempting to export AES keys fails in the expected way.
+ */
+TEST_F(ExportKeyTest, AesKeyUnexportable) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .EcbMode()
+                                             .Padding(PaddingMode::NONE)));
+
+    HidlBuf export_data;
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::X509, &export_data));
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::PKCS8, &export_data));
+    EXPECT_EQ(ErrorCode::UNSUPPORTED_KEY_FORMAT, ExportKey(KeyFormat::RAW, &export_data));
+}
+
+class ImportKeyTest : public KeymasterHidlTest {
+   public:
+    template <TagType tag_type, Tag tag, typename ValueT>
+    void CheckCryptoParam(TypedTag<tag_type, tag> ttag, ValueT expected) {
+        SCOPED_TRACE("CheckCryptoParam");
+        if (IsSecure()) {
+            EXPECT_TRUE(contains(key_characteristics_.hardwareEnforced, ttag, expected))
+                << "Tag " << tag << " with value " << expected << " not found";
+            EXPECT_FALSE(contains(key_characteristics_.softwareEnforced, ttag))
+                << "Tag " << tag << " found";
+        } else {
+            EXPECT_TRUE(contains(key_characteristics_.softwareEnforced, ttag, expected))
+                << "Tag " << tag << " with value " << expected << " not found";
+            EXPECT_FALSE(contains(key_characteristics_.hardwareEnforced, ttag))
+                << "Tag " << tag << " found";
+        }
+    }
+
+    void CheckOrigin() {
+        SCOPED_TRACE("CheckOrigin");
+        if (IsSecure()) {
+            EXPECT_TRUE(
+                contains(key_characteristics_.hardwareEnforced, TAG_ORIGIN, KeyOrigin::IMPORTED));
+        } else {
+            EXPECT_TRUE(
+                contains(key_characteristics_.softwareEnforced, TAG_ORIGIN, KeyOrigin::IMPORTED));
+        }
+    }
+};
+
+/*
+ * ImportKeyTest.RsaSuccess
+ *
+ * Verifies that importing and using an RSA key pair works correctly.
+ */
+TEST_F(ImportKeyTest, RsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .RsaSigningKey(1024, 65537)
+                                           .Digest(Digest::SHA_2_256)
+                                           .Padding(PaddingMode::RSA_PSS),
+                                       KeyFormat::PKCS8, rsa_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
+    CheckCryptoParam(TAG_KEY_SIZE, 1024U);
+    CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_PSS);
+    CheckOrigin();
+
+    string message(1024 / 8, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_PSS);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.RsaKeySizeMismatch
+ *
+ * Verifies that importing an RSA key pair with a size that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_F(ImportKeyTest, RsaKeySizeMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .RsaSigningKey(2048 /* Doesn't match key */, 65537)
+                            .Digest(Digest::NONE)
+                            .Padding(PaddingMode::NONE),
+                        KeyFormat::PKCS8, rsa_key));
+}
+
+/*
+ * ImportKeyTest.RsaPublicExponentMismatch
+ *
+ * Verifies that importing an RSA key pair with a public exponent that doesn't match the key fails
+ * in the correct way.
+ */
+TEST_F(ImportKeyTest, RsaPublicExponentMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .RsaSigningKey(1024, 3 /* Doesn't match key */)
+                            .Digest(Digest::NONE)
+                            .Padding(PaddingMode::NONE),
+                        KeyFormat::PKCS8, rsa_key));
+}
+
+/*
+ * ImportKeyTest.EcdsaSuccess
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair works correctly.
+ */
+TEST_F(ImportKeyTest, EcdsaSuccess) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .EcdsaSigningKey(256)
+                                           .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_256_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_KEY_SIZE, 256U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.Ecdsa521Success
+ *
+ * Verifies that importing and using an ECDSA P-521 key pair works correctly.
+ */
+TEST_F(ImportKeyTest, Ecdsa521Success) {
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .EcdsaSigningKey(521)
+                                           .Digest(Digest::SHA_2_256),
+                                       KeyFormat::PKCS8, ec_521_key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+    CheckCryptoParam(TAG_KEY_SIZE, 521U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_521);
+    CheckOrigin();
+
+    string message(32, 'a');
+    auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+    string signature = SignMessage(message, params);
+    VerifyMessage(message, signature, params);
+}
+
+/*
+ * ImportKeyTest.EcdsaSizeMismatch
+ *
+ * Verifies that importing an ECDSA key pair with a size that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_F(ImportKeyTest, EcdsaSizeMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .EcdsaSigningKey(224 /* Doesn't match key */)
+                            .Digest(Digest::NONE),
+                        KeyFormat::PKCS8, ec_256_key));
+}
+
+/*
+ * ImportKeyTest.EcdsaCurveMismatch
+ *
+ * Verifies that importing an ECDSA key pair with a curve that doesn't match the key fails in the
+ * correct way.
+ */
+TEST_F(ImportKeyTest, EcdsaCurveMismatch) {
+    ASSERT_EQ(ErrorCode::IMPORT_PARAMETER_MISMATCH,
+              ImportKey(AuthorizationSetBuilder()
+                            .EcdsaSigningKey(EcCurve::P_224 /* Doesn't match key */)
+                            .Digest(Digest::NONE),
+                        KeyFormat::PKCS8, ec_256_key));
+}
+
+/*
+ * ImportKeyTest.AesSuccess
+ *
+ * Verifies that importing and using an AES key works.
+ */
+TEST_F(ImportKeyTest, AesSuccess) {
+    string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .AesEncryptionKey(key.size() * 8)
+                                           .EcbMode()
+                                           .Padding(PaddingMode::PKCS7),
+                                       KeyFormat::RAW, key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::AES);
+    CheckCryptoParam(TAG_KEY_SIZE, 128U);
+    CheckCryptoParam(TAG_PADDING, PaddingMode::PKCS7);
+    CheckCryptoParam(TAG_BLOCK_MODE, BlockMode::ECB);
+    CheckOrigin();
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+    string ciphertext = EncryptMessage(message, params);
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * ImportKeyTest.AesSuccess
+ *
+ * Verifies that importing and using an HMAC key works.
+ */
+TEST_F(ImportKeyTest, HmacKeySuccess) {
+    string key = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+    ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+                                           .Authorization(TAG_NO_AUTH_REQUIRED)
+                                           .HmacKey(key.size() * 8)
+                                           .Digest(Digest::SHA_2_256)
+                                           .Authorization(TAG_MIN_MAC_LENGTH, 256),
+                                       KeyFormat::RAW, key));
+
+    CheckCryptoParam(TAG_ALGORITHM, Algorithm::HMAC);
+    CheckCryptoParam(TAG_KEY_SIZE, 128U);
+    CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+    CheckOrigin();
+
+    string message = "Hello World!";
+    string signature = MacMessage(message, Digest::SHA_2_256, 256);
+    VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
+}
+
+auto wrapped_key = hex2str(
+    "30820173020100048201006F5C273914D9E7EAB667FE62456A57DE64BED4A57DB3EFBB77E6907C82CC36B0BD12CB8A"
+    "85F3F8BC08A26C58186DB5C35636063388A04AE5579D3BDC057F9BB0EB6FDDA5E836DBB1F18A4546A64BA06E3D0132"
+    "AAA3306676638C786FAF0722E6E4145E0C91B009C422691F9F42F9F179DA93E16E7793DE5960E77A387433F0B43E49"
+    "3A7CF77ECA25BA724CC02F916D5792CAA76BC0756D3DB5D110D209B8B30285E9653D91FD89E953F351D82ACE1422CC"
+    "A146F8BD0C2F4CC32D1F81D894F4650043DB46109869696319A1A011BB003F2EBD8FA20B4A43F3226C1F182A39AE81"
+    "A35B9B7590A48B6A6874C9CC0EE0CD9528FB908688B4111932DF478CD7A92B50040CD796B02C370F1FA4CC0124F130"
+    "280201033023A1083106020100020101A203020120A30402020100A4053103020101A60531030201400420CCD54085"
+    "5F833A5E1480BFD2D36FAF3AEEE15DF5BEABE2691BC82DDE2A7AA91004107CB81BDDCD09E8F4DF575726279F3229");
+
+auto wrapped_key_masked = hex2str(
+    "30820173020100048201009059BB6E48F8036ABE1800D9C74F3DB5F20448F035C2C78AFBCC28AF26581061298CAC78"
+    "A8CA5B79721B60B74490555168488ED696C8930D00463C6FC81BF0B6E4E26C93E018D0E3DC8754C6B261E0A7C3A6DA"
+    "1A223EB59ACA8E13348F14B9E944AF3C224906C1ABFE21ADDEE81FC641D45E092C6B0A75A9BA56C05529AE47ECA0D5"
+    "CD3568501CF04D47391FC695EDE19A3022B347D1BDC6C792A08AA014F87DD4BBD44777B14D7D2273191DDCFE4E8512"
+    "EFA677A14E68E5D820C5513331D687C08B6317FA64D404231D05C74CDD9AEB89D253FBE07154B2080CF4ACA5E1EFCB"
+    "53EB193E8A01DD5F9634B65EF9B49899003E245FDA6A3B137FAC1263E55A6E1D040C6D9721D08589581AB49204A330"
+    "280201033023A1083106020100020101A203020120A30402020100A4053103020101A60531030201400420A61C6E24"
+    "7E25B3E6E69AA78EB03C2D4AC20D1F99A9A024A76F35C8E2CAB9B68D04101FF7A0E793B9EE4AECEBB9AC4C545254");
+
+auto wrapping_key = hex2str(
+    "308204be020100300d06092a864886f70d0101010500048204a8308204a40201000282010100aec367931d8900ce56"
+    "b0067f7d70e1fc653f3f34d194c1fed50018fb43db937b06e673a837313d56b1c725150a3fef86acbddc41bb759c28"
+    "54eae32d35841efb5c18d82bc90a1cb5c1d55adf245b02911f0b7cda88c421ff0ebafe7c0d23be312d7bd5921ffaea"
+    "1347c157406fef718f682643e4e5d33c6703d61c0cf7ac0bf4645c11f5c1374c3886427411c449796792e0bef75dec"
+    "858a2123c36753e02a95a96d7c454b504de385a642e0dfc3e60ac3a7ee4991d0d48b0172a95f9536f02ba13cecccb9"
+    "2b727db5c27e5b2f5cec09600b286af5cf14c42024c61ddfe71c2a8d7458f185234cb00e01d282f10f8fc6721d2aed"
+    "3f4833cca2bd8fa62821dd55020301000102820100431447b6251908112b1ee76f99f3711a52b6630960046c2de70d"
+    "e188d833f8b8b91e4d785caeeeaf4f0f74414e2cda40641f7fe24f14c67a88959bdb27766df9e710b630a03adc683b"
+    "5d2c43080e52bee71e9eaeb6de297a5fea1072070d181c822bccff087d63c940ba8a45f670feb29fb4484d1c95e6d2"
+    "579ba02aae0a00900c3ebf490e3d2cd7ee8d0e20c536e4dc5a5097272888cddd7e91f228b1c4d7474c55b8fcd618c4"
+    "a957bbddd5ad7407cc312d8d98a5caf7e08f4a0d6b45bb41c652659d5a5ba05b663737a8696281865ba20fbdd7f851"
+    "e6c56e8cbe0ddbbf24dc03b2d2cb4c3d540fb0af52e034a2d06698b128e5f101e3b51a34f8d8b4f8618102818100de"
+    "392e18d682c829266cc3454e1d6166242f32d9a1d10577753e904ea7d08bff841be5bac82a164c5970007047b8c517"
+    "db8f8f84e37bd5988561bdf503d4dc2bdb38f885434ae42c355f725c9a60f91f0788e1f1a97223b524b5357fdf72e2"
+    "f696bab7d78e32bf92ba8e1864eab1229e91346130748a6e3c124f9149d71c743502818100c95387c0f9d35f137b57"
+    "d0d65c397c5e21cc251e47008ed62a542409c8b6b6ac7f8967b3863ca645fcce49582a9aa17349db6c4a95affdae0d"
+    "ae612e1afac99ed39a2d934c880440aed8832f9843163a47f27f392199dc1202f9a0f9bd08308007cb1e4e7f583093"
+    "66a7de25f7c3c9b880677c068e1be936e81288815252a8a102818057ff8ca1895080b2cae486ef0adfd791fb0235c0"
+    "b8b36cd6c136e52e4085f4ea5a063212a4f105a3764743e53281988aba073f6e0027298e1c4378556e0efca0e14ece"
+    "1af76ad0b030f27af6f0ab35fb73a060d8b1a0e142fa2647e93b32e36d8282ae0a4de50ab7afe85500a16f43a64719"
+    "d6e2b9439823719cd08bcd03178102818100ba73b0bb28e3f81e9bd1c568713b101241acc607976c4ddccc90e65b65"
+    "56ca31516058f92b6e09f3b160ff0e374ec40d78ae4d4979fde6ac06a1a400c61dd31254186af30b22c10582a8a43e"
+    "34fe949c5f3b9755bae7baa7b7b7a6bd03b38cef55c86885fc6c1978b9cee7ef33da507c9df6b9277cff1e6aaa5d57"
+    "aca528466102818100c931617c77829dfb1270502be9195c8f2830885f57dba869536811e6864236d0c4736a0008a1"
+    "45af36b8357a7c3d139966d04c4e00934ea1aede3bb6b8ec841dc95e3f579751e2bfdfe27ae778983f959356210723"
+    "287b0affcc9f727044d48c373f1babde0724fa17a4fd4da0902c7c9b9bf27ba61be6ad02dfddda8f4e6822");
+
+string zero_masking_key =
+    hex2str("0000000000000000000000000000000000000000000000000000000000000000");
+string masking_key = hex2str("D796B02C370F1FA4CC0124F14EC8CBEBE987E825246265050F399A51FD477DFC");
+
+class ImportWrappedKeyTest : public KeymasterHidlTest {};
+
+TEST_F(ImportWrappedKeyTest, Success) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                 .RsaEncryptionKey(2048, 65537)
+                                 .Digest(Digest::SHA1)
+                                 .Padding(PaddingMode::RSA_OAEP)
+                                 .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+    ASSERT_EQ(ErrorCode::OK,
+              ImportWrappedKey(
+                  wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key,
+                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+    string ciphertext = EncryptMessage(message, params);
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+TEST_F(ImportWrappedKeyTest, SuccessMasked) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                 .RsaEncryptionKey(2048, 65537)
+                                 .Digest(Digest::SHA1)
+                                 .Padding(PaddingMode::RSA_OAEP)
+                                 .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+    ASSERT_EQ(ErrorCode::OK,
+              ImportWrappedKey(
+                  wrapped_key_masked, wrapping_key, wrapping_key_desc, masking_key,
+                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+}
+
+TEST_F(ImportWrappedKeyTest, WrongMask) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                 .RsaEncryptionKey(2048, 65537)
+                                 .Digest(Digest::SHA1)
+                                 .Padding(PaddingMode::RSA_OAEP)
+                                 .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+    ASSERT_EQ(ErrorCode::VERIFICATION_FAILED,
+              ImportWrappedKey(
+                  wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key,
+                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+}
+
+TEST_F(ImportWrappedKeyTest, WrongPurpose) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                 .RsaEncryptionKey(2048, 65537)
+                                 .Digest(Digest::SHA1)
+                                 .Padding(PaddingMode::RSA_OAEP);
+
+    ASSERT_EQ(ErrorCode::INCOMPATIBLE_PURPOSE,
+              ImportWrappedKey(
+                  wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key,
+                  AuthorizationSetBuilder().Digest(Digest::SHA1).Padding(PaddingMode::RSA_OAEP)));
+}
+
+typedef KeymasterHidlTest EncryptionOperationsTest;
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingSuccess
+ *
+ * Verifies that raw RSA encryption works.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message = string(1024 / 8, 'a');
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    string ciphertext1 = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext2.size());
+
+    // Unpadded RSA is deterministic
+    EXPECT_EQ(ciphertext1, ciphertext2);
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingShortMessage
+ *
+ * Verifies that raw RSA encryption of short messages works.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingShortMessage) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message = "1";
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+
+    string ciphertext = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext.size());
+
+    string expected_plaintext = string(1024 / 8 - 1, 0) + message;
+    string plaintext = DecryptMessage(ciphertext, params);
+
+    EXPECT_EQ(expected_plaintext, plaintext);
+
+    // Degenerate case, encrypting a numeric 1 yields 0x00..01 as the ciphertext.
+    message = static_cast<char>(1);
+    ciphertext = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext.size());
+    EXPECT_EQ(ciphertext, string(1024 / 8 - 1, 0) + message);
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingTooLong
+ *
+ * Verifies that raw RSA encryption of too-long messages fails in the expected way.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLong) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message(1024 / 8 + 1, 'a');
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+
+    string result;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &result));
+}
+
+/*
+ * EncryptionOperationsTest.RsaNoPaddingTooLarge
+ *
+ * Verifies that raw RSA encryption of too-large (numerically) messages fails in the expected way.
+ */
+TEST_F(EncryptionOperationsTest, RsaNoPaddingTooLarge) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::NONE)));
+
+    HidlBuf exported;
+    ASSERT_EQ(ErrorCode::OK, ExportKey(KeyFormat::X509, &exported));
+
+    const uint8_t* p = exported.data();
+    EVP_PKEY_Ptr pkey(d2i_PUBKEY(nullptr /* alloc new */, &p, exported.size()));
+    RSA_Ptr rsa(EVP_PKEY_get1_RSA(pkey.get()));
+
+    size_t modulus_len = BN_num_bytes(rsa->n);
+    ASSERT_EQ(1024U / 8, modulus_len);
+    std::unique_ptr<uint8_t[]> modulus_buf(new uint8_t[modulus_len]);
+    BN_bn2bin(rsa->n, modulus_buf.get());
+
+    // The modulus is too big to encrypt.
+    string message(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+
+    string result;
+    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+
+    // One smaller than the modulus is okay.
+    BN_sub(rsa->n, rsa->n, BN_value_one());
+    modulus_len = BN_num_bytes(rsa->n);
+    ASSERT_EQ(1024U / 8, modulus_len);
+    BN_bn2bin(rsa->n, modulus_buf.get());
+    message = string(reinterpret_cast<const char*>(modulus_buf.get()), modulus_len);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+    EXPECT_EQ(ErrorCode::OK, Finish(message, &result));
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepSuccess
+ *
+ * Verifies that RSA-OAEP encryption operations work, with all digests.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepSuccess) {
+    auto digests = {Digest::MD5,       Digest::SHA1,      Digest::SHA_2_224,
+                    Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512};
+
+    size_t key_size = 2048;  // Need largish key for SHA-512 test.
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(key_size, 3)
+                                             .Padding(PaddingMode::RSA_OAEP)
+                                             .Digest(digests)));
+
+    string message = "Hello";
+
+    for (auto digest : digests) {
+        auto params = AuthorizationSetBuilder().Digest(digest).Padding(PaddingMode::RSA_OAEP);
+        string ciphertext1 = EncryptMessage(message, params);
+        if (HasNonfatalFailure()) std::cout << "-->" << digest << std::endl;
+        EXPECT_EQ(key_size / 8, ciphertext1.size());
+
+        string ciphertext2 = EncryptMessage(message, params);
+        EXPECT_EQ(key_size / 8, ciphertext2.size());
+
+        // OAEP randomizes padding so every result should be different (with astronomically high
+        // probability).
+        EXPECT_NE(ciphertext1, ciphertext2);
+
+        string plaintext1 = DecryptMessage(ciphertext1, params);
+        EXPECT_EQ(message, plaintext1) << "RSA-OAEP failed with digest " << digest;
+        string plaintext2 = DecryptMessage(ciphertext2, params);
+        EXPECT_EQ(message, plaintext2) << "RSA-OAEP failed with digest " << digest;
+
+        // Decrypting corrupted ciphertext should fail.
+        size_t offset_to_corrupt = random() % ciphertext1.size();
+        char corrupt_byte;
+        do {
+            corrupt_byte = static_cast<char>(random() % 256);
+        } while (corrupt_byte == ciphertext1[offset_to_corrupt]);
+        ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+        EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+        string result;
+        EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+        EXPECT_EQ(0U, result.size());
+    }
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepInvalidDigest
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to operate
+ * without a digest.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepInvalidDigest) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::RSA_OAEP)
+                                             .Digest(Digest::NONE)));
+    string message = "Hello World!";
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_DIGEST, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepInvalidDigest
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to decrypt with a
+ * different digest than was used to encrypt.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::RSA_OAEP)
+                                             .Digest(Digest::SHA_2_256, Digest::SHA_2_224)));
+    string message = "Hello World!";
+    string ciphertext = EncryptMessage(
+        message,
+        AuthorizationSetBuilder().Digest(Digest::SHA_2_224).Padding(PaddingMode::RSA_OAEP));
+
+    EXPECT_EQ(
+        ErrorCode::OK,
+        Begin(KeyPurpose::DECRYPT,
+              AuthorizationSetBuilder().Digest(Digest::SHA_2_256).Padding(PaddingMode::RSA_OAEP)));
+    string result;
+    EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result));
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaOaepTooLarge
+ *
+ * Verifies that RSA-OAEP encryption operations fail in the correct way when asked to encrypt a
+ * too-large message.
+ */
+TEST_F(EncryptionOperationsTest, RsaOaepTooLarge) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::RSA_OAEP)
+                                             .Digest(Digest::SHA1)));
+    constexpr size_t digest_size = 160 /* SHA1 */ / 8;
+    constexpr size_t oaep_overhead = 2 * digest_size + 2;
+    string message(1024 / 8 - oaep_overhead + 1, 'a');
+    EXPECT_EQ(ErrorCode::OK,
+              Begin(KeyPurpose::ENCRYPT,
+                    AuthorizationSetBuilder().Padding(PaddingMode::RSA_OAEP).Digest(Digest::SHA1)));
+    string result;
+    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaPkcs1Success
+ *
+ * Verifies that RSA PKCS encryption/decrypts works.
+ */
+TEST_F(EncryptionOperationsTest, RsaPkcs1Success) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)));
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+    string ciphertext1 = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(message, params);
+    EXPECT_EQ(1024U / 8, ciphertext2.size());
+
+    // PKCS1 v1.5 randomizes padding so every result should be different.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Decrypting corrupted ciphertext should fail.
+    size_t offset_to_corrupt = random() % ciphertext1.size();
+    char corrupt_byte;
+    do {
+        corrupt_byte = static_cast<char>(random() % 256);
+    } while (corrupt_byte == ciphertext1[offset_to_corrupt]);
+    ciphertext1[offset_to_corrupt] = corrupt_byte;
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string result;
+    EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.RsaPkcs1TooLarge
+ *
+ * Verifies that RSA PKCS encryption fails in the correct way when the mssage is too large.
+ */
+TEST_F(EncryptionOperationsTest, RsaPkcs1TooLarge) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaEncryptionKey(1024, 3)
+                                             .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)));
+    string message(1024 / 8 - 10, 'a');
+
+    auto params = AuthorizationSetBuilder().Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+    string result;
+    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(message, &result));
+    EXPECT_EQ(0U, result.size());
+}
+
+/*
+ * EncryptionOperationsTest.EcdsaEncrypt
+ *
+ * Verifies that attempting to use ECDSA keys to encrypt fails in the correct way.
+ */
+TEST_F(EncryptionOperationsTest, EcdsaEncrypt) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(224)
+                                             .Digest(Digest::NONE)));
+    auto params = AuthorizationSetBuilder().Digest(Digest::NONE);
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params));
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.HmacEncrypt
+ *
+ * Verifies that attempting to use HMAC keys to encrypt fails in the correct way.
+ */
+TEST_F(EncryptionOperationsTest, HmacEncrypt) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .HmacKey(128)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    auto params = AuthorizationSetBuilder()
+                      .Digest(Digest::SHA_2_256)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 128);
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::ENCRYPT, params));
+    ASSERT_EQ(ErrorCode::UNSUPPORTED_PURPOSE, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbRoundTripSuccess
+ *
+ * Verifies that AES ECB mode works.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    string ciphertext1 = EncryptMessage(message, params);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(string(message), params);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // ECB is deterministic.
+    EXPECT_EQ(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbRoundTripSuccess
+ *
+ * Verifies that AES encryption fails in the correct way when an unauthorized mode is specified.
+ */
+TEST_F(EncryptionOperationsTest, AesWrongMode) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    EXPECT_EQ(
+        ErrorCode::INCOMPATIBLE_BLOCK_MODE,
+        Begin(KeyPurpose::ENCRYPT,
+              AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE)));
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbNoPaddingWrongInputSize
+ *
+ * Verifies that AES encryption fails in the correct way when provided an input that is not a
+ * multiple of the block size and no padding is specified.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbNoPaddingWrongInputSize) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                             .Padding(PaddingMode::NONE)));
+    // Message is slightly shorter than two blocks.
+    string message(16 * 2 - 1, 'a');
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &ciphertext));
+    EXPECT_EQ(0U, ciphertext.size());
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7Padding
+ *
+ * Verifies that AES PKCS7 padding works for any message length.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+    // Try various message lengths; all should work.
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        string ciphertext = EncryptMessage(message, params);
+        EXPECT_EQ(i + 16 - (i % 16), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, params);
+        EXPECT_EQ(message, plaintext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbWrongPadding
+ *
+ * Verifies that AES enryption fails in the correct way when an unauthorized padding mode is
+ * specified.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbWrongPadding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+    // Try various message lengths; all should fail
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7PaddingCorrupted
+ *
+ * Verifies that AES decryption fails in the correct way when the padding is corrupted.
+ */
+TEST_F(EncryptionOperationsTest, AesEcbPkcs7PaddingCorrupted) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+    string message = "a";
+    string ciphertext = EncryptMessage(message, params);
+    EXPECT_EQ(16U, ciphertext.size());
+    EXPECT_NE(ciphertext, message);
+    ++ciphertext[ciphertext.size() / 2];
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, &plaintext));
+}
+
+HidlBuf CopyIv(const AuthorizationSet& set) {
+    auto iv = set.GetTagValue(TAG_NONCE);
+    EXPECT_TRUE(iv.isOk());
+    return iv.value();
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrRoundTripSuccess
+ *
+ * Verifies that AES CTR mode works.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE);
+
+    string message = "123";
+    AuthorizationSet out_params;
+    string ciphertext1 = EncryptMessage(message, params, &out_params);
+    HidlBuf iv1 = CopyIv(out_params);
+    EXPECT_EQ(16U, iv1.size());
+
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    out_params.Clear();
+    string ciphertext2 = EncryptMessage(message, params, &out_params);
+    HidlBuf iv2 = CopyIv(out_params);
+    EXPECT_EQ(16U, iv2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    auto params_iv1 =
+        AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv1);
+    auto params_iv2 =
+        AuthorizationSetBuilder().Authorizations(params).Authorization(TAG_NONCE, iv2);
+
+    string plaintext = DecryptMessage(ciphertext1, params_iv1);
+    EXPECT_EQ(message, plaintext);
+    plaintext = DecryptMessage(ciphertext2, params_iv2);
+    EXPECT_EQ(message, plaintext);
+
+    // Using the wrong IV will result in a "valid" decryption, but the data will be garbage.
+    plaintext = DecryptMessage(ciphertext1, params_iv2);
+    EXPECT_NE(message, plaintext);
+    plaintext = DecryptMessage(ciphertext2, params_iv1);
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesIncremental
+ *
+ * Verifies that AES works, all modes, when provided data in various size increments.
+ */
+TEST_F(EncryptionOperationsTest, AesIncremental) {
+    auto block_modes = {
+        BlockMode::ECB, BlockMode::CBC, BlockMode::CTR, BlockMode::GCM,
+    };
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(block_modes)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    for (int increment = 1; increment <= 240; ++increment) {
+        for (auto block_mode : block_modes) {
+            string message(240, 'a');
+            auto params = AuthorizationSetBuilder()
+                              .BlockMode(block_mode)
+                              .Padding(PaddingMode::NONE)
+                              .Authorization(TAG_MAC_LENGTH, 128) /* for GCM */;
+
+            AuthorizationSet output_params;
+            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &output_params));
+
+            string ciphertext;
+            size_t input_consumed;
+            string to_send;
+            for (size_t i = 0; i < message.size(); i += increment) {
+                to_send.append(message.substr(i, increment));
+                EXPECT_EQ(ErrorCode::OK, Update(to_send, &ciphertext, &input_consumed));
+                to_send = to_send.substr(input_consumed);
+
+                switch (block_mode) {
+                    case BlockMode::ECB:
+                    case BlockMode::CBC:
+                        // Implementations must take as many blocks as possible, leaving less than
+                        // a block.
+                        EXPECT_LE(to_send.length(), 16U);
+                        break;
+                    case BlockMode::GCM:
+                    case BlockMode::CTR:
+                        // Implementations must always take all the data.
+                        EXPECT_EQ(0U, to_send.length());
+                        break;
+                }
+            }
+            EXPECT_EQ(ErrorCode::OK, Finish(to_send, &ciphertext)) << "Error sending " << to_send;
+
+            switch (block_mode) {
+                case BlockMode::GCM:
+                    EXPECT_EQ(message.size() + 16, ciphertext.size());
+                    break;
+                case BlockMode::CTR:
+                    EXPECT_EQ(message.size(), ciphertext.size());
+                    break;
+                case BlockMode::CBC:
+                case BlockMode::ECB:
+                    EXPECT_EQ(message.size() + message.size() % 16, ciphertext.size());
+                    break;
+            }
+
+            auto iv = output_params.GetTagValue(TAG_NONCE);
+            switch (block_mode) {
+                case BlockMode::CBC:
+                case BlockMode::GCM:
+                case BlockMode::CTR:
+                    ASSERT_TRUE(iv.isOk()) << "No IV for block mode " << block_mode;
+                    EXPECT_EQ(block_mode == BlockMode::GCM ? 12U : 16U, iv.value().size());
+                    params.push_back(TAG_NONCE, iv.value());
+                    break;
+
+                case BlockMode::ECB:
+                    EXPECT_FALSE(iv.isOk()) << "ECB mode should not generate IV";
+                    break;
+            }
+
+            EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params))
+                << "Decrypt begin() failed for block mode " << block_mode;
+
+            string plaintext;
+            for (size_t i = 0; i < ciphertext.size(); i += increment) {
+                to_send.append(ciphertext.substr(i, increment));
+                EXPECT_EQ(ErrorCode::OK, Update(to_send, &plaintext, &input_consumed));
+                to_send = to_send.substr(input_consumed);
+            }
+            ErrorCode error = Finish(to_send, &plaintext);
+            ASSERT_EQ(ErrorCode::OK, error) << "Decryption failed for block mode " << block_mode
+                                            << " and increment " << increment;
+            if (error == ErrorCode::OK) {
+                ASSERT_EQ(message, plaintext) << "Decryption didn't match for block mode "
+                                              << block_mode << " and increment " << increment;
+            }
+        }
+    }
+}
+
+struct AesCtrSp80038aTestVector {
+    const char* key;
+    const char* nonce;
+    const char* plaintext;
+    const char* ciphertext;
+};
+
+// These test vectors are taken from
+// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section F.5.
+static const AesCtrSp80038aTestVector kAesCtrSp80038aTestVectors[] = {
+    // AES-128
+    {
+        "2b7e151628aed2a6abf7158809cf4f3c", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+        "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+        "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff"
+        "5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee",
+    },
+    // AES-192
+    {
+        "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b", "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+        "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+        "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e94"
+        "1e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050",
+    },
+    // AES-256
+    {
+        "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
+        "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+        "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"
+        "30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710",
+        "601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5"
+        "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6",
+    },
+};
+
+/*
+ * EncryptionOperationsTest.AesCtrSp80038aTestVector
+ *
+ * Verifies AES CTR implementation against SP800-38A test vectors.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrSp80038aTestVector) {
+    for (size_t i = 0; i < 3; i++) {
+        const AesCtrSp80038aTestVector& test(kAesCtrSp80038aTestVectors[i]);
+        const string key = hex2str(test.key);
+        const string nonce = hex2str(test.nonce);
+        const string plaintext = hex2str(test.plaintext);
+        const string ciphertext = hex2str(test.ciphertext);
+        CheckAesCtrTestVector(key, nonce, plaintext, ciphertext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrIncompatiblePaddingMode
+ *
+ * Verifies that keymaster rejects use of CTR mode with PKCS7 padding in the correct way.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrIncompatiblePaddingMode) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+                                             .Padding(PaddingMode::PKCS7)));
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CTR).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrInvalidCallerNonce
+ *
+ * Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
+ */
+TEST_F(EncryptionOperationsTest, AesCtrInvalidCallerNonce) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CTR)
+                                             .Authorization(TAG_CALLER_NONCE)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::CTR)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_NONCE, HidlBuf(string(1, 'a')));
+    EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+
+    params = AuthorizationSetBuilder()
+                 .BlockMode(BlockMode::CTR)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_NONCE, HidlBuf(string(15, 'a')));
+    EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+
+    params = AuthorizationSetBuilder()
+                 .BlockMode(BlockMode::CTR)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_NONCE, HidlBuf(string(17, 'a')));
+    EXPECT_EQ(ErrorCode::INVALID_NONCE, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesCtrInvalidCallerNonce
+ *
+ * Verifies that keymaster fails correctly when the user supplies an incorrect-size nonce.
+ */
+TEST_F(EncryptionOperationsTest, AesCbcRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+    // Two-block message.
+    string message = "12345678901234567890123456789012";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext1 = EncryptMessage(message, params, &out_params);
+    HidlBuf iv1 = CopyIv(out_params);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    out_params.Clear();
+
+    string ciphertext2 = EncryptMessage(message, params, &out_params);
+    HidlBuf iv2 = CopyIv(out_params);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    params.push_back(TAG_NONCE, iv1);
+    string plaintext = DecryptMessage(ciphertext1, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesCallerNonce
+ *
+ * Verifies that AES caller-provided nonces work correctly.
+ */
+TEST_F(EncryptionOperationsTest, AesCallerNonce) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                             .Authorization(TAG_CALLER_NONCE)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message = "12345678901234567890123456789012";
+
+    // Don't specify nonce, should get a random one.
+    AuthorizationSetBuilder params =
+        AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_EQ(message.size(), ciphertext.size());
+    EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
+
+    params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should also work.
+    params = AuthorizationSetBuilder()
+                 .BlockMode(BlockMode::CBC)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_NONCE, HidlBuf("abcdefghijklmnop"));
+    out_params.Clear();
+    ciphertext = EncryptMessage(message, params, &out_params);
+
+    // Decrypt with correct nonce.
+    plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Try with wrong nonce.
+    params = AuthorizationSetBuilder()
+                 .BlockMode(BlockMode::CBC)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_NONCE, HidlBuf("aaaaaaaaaaaaaaaa"));
+    plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesCallerNonceProhibited
+ *
+ * Verifies that caller-provided nonces are not permitted when not specified in the key
+ * authorizations.
+ */
+TEST_F(EncryptionOperationsTest, AesCallerNonceProhibited) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message = "12345678901234567890123456789012";
+
+    // Don't specify nonce, should get a random one.
+    AuthorizationSetBuilder params =
+        AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet out_params;
+    string ciphertext = EncryptMessage(message, params, &out_params);
+    EXPECT_EQ(message.size(), ciphertext.size());
+    EXPECT_EQ(16U, out_params.GetTagValue(TAG_NONCE).value().size());
+
+    params.push_back(TAG_NONCE, out_params.GetTagValue(TAG_NONCE).value());
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should fail
+    params = AuthorizationSetBuilder()
+                 .BlockMode(BlockMode::CBC)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_NONCE, HidlBuf("abcdefghijklmnop"));
+    out_params.Clear();
+    EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED, Begin(KeyPurpose::ENCRYPT, params, &out_params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmRoundTripSuccess
+ *
+ * Verifies that AES GCM mode works.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto update_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params))
+        << "Begin encrypt";
+    string ciphertext;
+    AuthorizationSet update_out_params;
+    ASSERT_EQ(ErrorCode::OK,
+              Finish(op_handle_, update_params, message, "", &update_out_params, &ciphertext));
+
+    // Grab nonce
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt.
+    ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params)) << "Begin decrypt";
+    string plaintext;
+    size_t input_consumed;
+    ASSERT_EQ(ErrorCode::OK, Update(op_handle_, update_params, ciphertext, &update_out_params,
+                                    &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(ErrorCode::OK, Finish("", &plaintext));
+
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmTooShortTag
+ *
+ * Verifies that AES GCM mode fails correctly when a too-short tag length is specified.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmTooShortTag) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string message = "123456789012345678901234567890123456";
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::GCM)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 96);
+
+    EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmTooShortTagOnDecrypt
+ *
+ * Verifies that AES GCM mode fails correctly when a too-short tag is provided to decryption.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmTooShortTagOnDecrypt) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+    string aad = "foobar";
+    string message = "123456789012345678901234567890123456";
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::GCM)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    EXPECT_EQ(1U, begin_out_params.size());
+    ASSERT_TRUE(begin_out_params.GetTagValue(TAG_NONCE).isOk());
+
+    AuthorizationSet finish_out_params;
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+
+    params = AuthorizationSetBuilder()
+                 .Authorizations(begin_out_params)
+                 .BlockMode(BlockMode::GCM)
+                 .Padding(PaddingMode::NONE)
+                 .Authorization(TAG_MAC_LENGTH, 96);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::INVALID_MAC_LENGTH, Begin(KeyPurpose::DECRYPT, params));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmCorruptKey
+ *
+ * Verifies that AES GCM mode fails correctly when the decryption key is incorrect.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmCorruptKey) {
+    const uint8_t nonce_bytes[] = {
+        0xb7, 0x94, 0x37, 0xae, 0x08, 0xff, 0x35, 0x5d, 0x7d, 0x8a, 0x4d, 0x0f,
+    };
+    string nonce = make_string(nonce_bytes);
+    const uint8_t ciphertext_bytes[] = {
+        0xb3, 0xf6, 0x79, 0x9e, 0x8f, 0x93, 0x26, 0xf2, 0xdf, 0x1e, 0x80, 0xfc, 0xd2, 0xcb, 0x16,
+        0xd7, 0x8c, 0x9d, 0xc7, 0xcc, 0x14, 0xbb, 0x67, 0x78, 0x62, 0xdc, 0x6c, 0x63, 0x9b, 0x3a,
+        0x63, 0x38, 0xd2, 0x4b, 0x31, 0x2d, 0x39, 0x89, 0xe5, 0x92, 0x0b, 0x5d, 0xbf, 0xc9, 0x76,
+        0x76, 0x5e, 0xfb, 0xfe, 0x57, 0xbb, 0x38, 0x59, 0x40, 0xa7, 0xa4, 0x3b, 0xdf, 0x05, 0xbd,
+        0xda, 0xe3, 0xc9, 0xd6, 0xa2, 0xfb, 0xbd, 0xfc, 0xc0, 0xcb, 0xa0,
+    };
+    string ciphertext = make_string(ciphertext_bytes);
+
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::GCM)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 128)
+                      .Authorization(TAG_NONCE, nonce.data(), nonce.size());
+
+    auto import_params = AuthorizationSetBuilder()
+                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                             .AesEncryptionKey(128)
+                             .BlockMode(BlockMode::GCM)
+                             .Padding(PaddingMode::NONE)
+                             .Authorization(TAG_CALLER_NONCE)
+                             .Authorization(TAG_MIN_MAC_LENGTH, 128);
+
+    // Import correct key and decrypt
+    const uint8_t key_bytes[] = {
+        0xba, 0x76, 0x35, 0x4f, 0x0a, 0xed, 0x6e, 0x8d,
+        0x91, 0xf4, 0x5c, 0x4f, 0xf5, 0xa0, 0x62, 0xdb,
+    };
+    string key = make_string(key_bytes);
+    ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key));
+    string plaintext = DecryptMessage(ciphertext, params);
+    CheckedDeleteKey();
+
+    // Corrupt key and attempt to decrypt
+    key[0] = 0;
+    ASSERT_EQ(ErrorCode::OK, ImportKey(import_params, KeyFormat::RAW, key));
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
+    CheckedDeleteKey();
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmAadNoData
+ *
+ * Verifies that AES GCM mode works when provided additional authenticated data, but no data to
+ * encrypt.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmAadNoData) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "1234567890123456";
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::GCM)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, "" /* input */, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+    EXPECT_TRUE(finish_out_params.empty());
+
+    // Grab nonce
+    params.push_back(begin_out_params);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, ciphertext, "" /* signature */,
+                                    &finish_out_params, &plaintext));
+
+    EXPECT_TRUE(finish_out_params.empty());
+
+    EXPECT_EQ("", plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmMultiPartAad
+ *
+ * Verifies that AES GCM mode works when provided additional authenticated data in multiple chunks.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmMultiPartAad) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "123456789012345678901234567890123456";
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+    AuthorizationSet begin_out_params;
+
+    auto update_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3);
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+
+    // No data, AAD only.
+    string ciphertext;
+    size_t input_consumed;
+    AuthorizationSet update_out_params;
+    EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, "" /* input */, &update_out_params,
+                                    &ciphertext, &input_consumed));
+    EXPECT_EQ(0U, input_consumed);
+    EXPECT_EQ(0U, ciphertext.size());
+    EXPECT_TRUE(update_out_params.empty());
+
+    // AAD and data.
+    EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, message, &update_out_params,
+                                    &ciphertext, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(message.size(), ciphertext.size());
+    EXPECT_TRUE(update_out_params.empty());
+
+    EXPECT_EQ(ErrorCode::OK, Finish("" /* input */, &ciphertext));
+
+    // Grab nonce.
+    begin_params.push_back(begin_out_params);
+
+    // Decrypt
+    update_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foofoo", (size_t)6);
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, update_params, ciphertext, "" /* signature */,
+                                    &update_out_params, &plaintext));
+    EXPECT_TRUE(update_out_params.empty());
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmAadOutOfOrder
+ *
+ * Verifies that AES GCM mode fails correctly when given AAD after data to encipher.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmAadOutOfOrder) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "123456789012345678901234567890123456";
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+    AuthorizationSet begin_out_params;
+
+    auto update_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foo", (size_t)3);
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+
+    // No data, AAD only.
+    string ciphertext;
+    size_t input_consumed;
+    AuthorizationSet update_out_params;
+    EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, "" /* input */, &update_out_params,
+                                    &ciphertext, &input_consumed));
+    EXPECT_EQ(0U, input_consumed);
+    EXPECT_EQ(0U, ciphertext.size());
+    EXPECT_TRUE(update_out_params.empty());
+
+    // AAD and data.
+    EXPECT_EQ(ErrorCode::OK, Update(op_handle_, update_params, message, &update_out_params,
+                                    &ciphertext, &input_consumed));
+    EXPECT_EQ(message.size(), input_consumed);
+    EXPECT_EQ(message.size(), ciphertext.size());
+    EXPECT_TRUE(update_out_params.empty());
+
+    // More AAD
+    EXPECT_EQ(ErrorCode::INVALID_TAG, Update(op_handle_, update_params, "", &update_out_params,
+                                             &ciphertext, &input_consumed));
+
+    op_handle_ = kOpHandleSentinel;
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmBadAad
+ *
+ * Verifies that AES GCM decryption fails correctly when additional authenticated date is wrong.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmBadAad) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "12345678901234567890123456789012";
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6);
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+
+    // Grab nonce
+    begin_params.push_back(begin_out_params);
+
+    finish_params = AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA,
+                                                            "barfoo" /* Wrong AAD */, (size_t)6);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED,
+              Finish(op_handle_, finish_params, ciphertext, "" /* signature */, &finish_out_params,
+                     &plaintext));
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmWrongNonce
+ *
+ * Verifies that AES GCM decryption fails correctly when the nonce is incorrect.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmWrongNonce) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string message = "12345678901234567890123456789012";
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::GCM)
+                            .Padding(PaddingMode::NONE)
+                            .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, "foobar", (size_t)6);
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+
+    // Wrong nonce
+    begin_params.push_back(TAG_NONCE, HidlBuf("123456789012"));
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED,
+              Finish(op_handle_, finish_params, ciphertext, "" /* signature */, &finish_out_params,
+                     &plaintext));
+
+    // With wrong nonce, should have gotten garbage plaintext (or none).
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.AesGcmCorruptTag
+ *
+ * Verifies that AES GCM decryption fails correctly when the tag is wrong.
+ */
+TEST_F(EncryptionOperationsTest, AesGcmCorruptTag) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .BlockMode(BlockMode::GCM)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    string aad = "1234567890123456";
+    string message = "123456789012345678901234567890123456";
+
+    auto params = AuthorizationSetBuilder()
+                      .BlockMode(BlockMode::GCM)
+                      .Padding(PaddingMode::NONE)
+                      .Authorization(TAG_MAC_LENGTH, 128);
+
+    auto finish_params =
+        AuthorizationSetBuilder().Authorization(TAG_ASSOCIATED_DATA, aad.data(), aad.size());
+
+    // Encrypt
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+    string ciphertext;
+    AuthorizationSet finish_out_params;
+    EXPECT_EQ(ErrorCode::OK, Finish(op_handle_, finish_params, message, "" /* signature */,
+                                    &finish_out_params, &ciphertext));
+    EXPECT_TRUE(finish_out_params.empty());
+
+    // Corrupt tag
+    ++(*ciphertext.rbegin());
+
+    // Grab nonce
+    params.push_back(begin_out_params);
+
+    // Decrypt.
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+    string plaintext;
+    EXPECT_EQ(ErrorCode::VERIFICATION_FAILED,
+              Finish(op_handle_, finish_params, ciphertext, "" /* signature */, &finish_out_params,
+                     &plaintext));
+    EXPECT_TRUE(finish_out_params.empty());
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbRoundTripSuccess
+ *
+ * Verifies that 3DES is basically functional.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) {
+    std::cout << "Hello" << std::endl;
+
+    auto auths = AuthorizationSetBuilder()
+                     .TripleDesEncryptionKey(112)
+                     .BlockMode(BlockMode::ECB)
+                     .Padding(PaddingMode::NONE);
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(auths));
+    // Two-block message.
+    string message = "1234567890123456";
+    auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+    string ciphertext1 = EncryptMessage(message, inParams);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(string(message), inParams);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // ECB is deterministic.
+    EXPECT_EQ(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, inParams);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbNotAuthorized
+ *
+ * Verifies that CBC keys reject ECB usage.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbNotAuthorized) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, inParams));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbPkcs7Padding
+ *
+ * Tests ECB mode with PKCS#7 padding, various message sizes.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::ECB)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        auto inParams =
+            AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+        string ciphertext = EncryptMessage(message, inParams);
+        EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, inParams);
+        EXPECT_EQ(message, plaintext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbNoPaddingKeyWithPkcs7Padding
+ *
+ * Verifies that keys configured for no padding reject PKCS7 padding
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::ECB)
+                                             .Padding(PaddingMode::NONE)));
+    for (size_t i = 0; i < 32; ++i) {
+        auto inParams =
+            AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+        EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, inParams));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbPkcs7PaddingCorrupted
+ *
+ * Verifies that corrupted padding is detected.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::ECB)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    string message = "a";
+    string ciphertext = EncryptMessage(message, BlockMode::ECB, PaddingMode::PKCS7);
+    EXPECT_EQ(8U, ciphertext.size());
+    EXPECT_NE(ciphertext, message);
+    ++ciphertext[ciphertext.size() / 2];
+
+    AuthorizationSetBuilder begin_params;
+    begin_params.push_back(TAG_BLOCK_MODE, BlockMode::ECB);
+    begin_params.push_back(TAG_PADDING, PaddingMode::PKCS7);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+    string plaintext;
+    size_t input_consumed;
+    EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+}
+
+struct TripleDesTestVector {
+    const char* name;
+    const KeyPurpose purpose;
+    const BlockMode block_mode;
+    const PaddingMode padding_mode;
+    const char* key;
+    const char* iv;
+    const char* input;
+    const char* output;
+};
+
+// These test vectors are from NIST CAVP, plus a few custom variants to test padding, since all of
+// the NIST vectors are multiples of the block size.
+static const TripleDesTestVector kTripleDesTestVectors[] = {
+    {
+        "TECBMMT2 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "ad192fd064b5579e7a4fb3c8f794f22a",  // key
+        "",                                  // IV
+        "13bad542f3652d67",                  // input
+        "908e543cf2cb254f",                  // output
+    },
+    {
+        "TECBMMT2 Encrypt 0 PKCS7", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::PKCS7,
+        "ad192fd064b5579e7a4fb3c8f794f22a",  // key
+        "",                                  // IV
+        "13bad542f3652d6700",                // input
+        "908e543cf2cb254fc40165289a89008c",  // output
+    },
+    {
+        "TECBMMT2 Encrypt 0 PKCS7 decrypted", KeyPurpose::DECRYPT, BlockMode::ECB,
+        PaddingMode::PKCS7,
+        "ad192fd064b5579e7a4fb3c8f794f22a",  // key
+        "",                                  // IV
+        "908e543cf2cb254fc40165289a89008c",  // input
+        "13bad542f3652d6700",                // output
+    },
+    {
+        "TECBMMT2 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "259df16e7af804fe83b90e9bf7c7e557",  // key
+        "",                                  // IV
+        "a4619c433bbd6787c07c81728f9ac9fa",  // input
+        "9e06de155c483c6bcfd834dbc8bd5830",  // output
+    },
+    {
+        "TECBMMT2 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "b32ff42092024adf2076b9d3d9f19e6d",  // key
+        "",                                  // IV
+        "2f3f2a49bba807a5",                  // input
+        "2249973fa135fb52",                  // output
+    },
+    {
+        "TECBMMT2 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "023dfbe6621aa17cc219eae9cdecd923",  // key
+        "",                                  // IV
+        "54045dc71d8d565b227ec19f06fef912",  // input
+        "9b071622181e6412de6066429401410d",  // output
+    },
+    {
+        "TECBMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "a2b5bc67da13dc92cd9d344aa238544a0e1fa79ef76810cd",  // key
+        "",                                                  // IV
+        "329d86bdf1bc5af4",                                  // input
+        "d946c2756d78633f",                                  // output
+    },
+    {
+        "TECBMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "49e692290d2a5e46bace79b9648a4c5d491004c262dc9d49",  // key
+        "",                                                  // IV
+        "6b1540781b01ce1997adae102dbf3c5b",                  // input
+        "4d0dc182d6e481ac4a3dc6ab6976ccae",                  // output
+    },
+    {
+        "TECBMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "52daec2ac7dc1958377392682f37860b2cc1ea2304bab0e9",  // key
+        "",                                                  // IV
+        "6daad94ce08acfe7",                                  // input
+        "660e7d32dcc90e79",                                  // output
+    },
+    {
+        "TECBMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "7f8fe3d3f4a48394fb682c2919926d6ddfce8932529229ce",  // key
+        "",                                                  // IV
+        "e9653a0a1f05d31b9acd12d73aa9879d",                  // input
+        "9b2ae9d998efe62f1b592e7e1df8ff38",                  // output
+    },
+    {
+        "TCBCMMT2 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "34a41a8c293176c1b30732ecfe38ae8a",  // key
+        "f55b4855228bd0b4",                  // IV
+        "7dd880d2a9ab411c",                  // input
+        "c91892948b6cadb4",                  // output
+    },
+    {
+        "TCBCMMT2 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "70a88fa1dfb9942fa77f40157ffef2ad",  // key
+        "ece08ce2fdc6ce80",                  // IV
+        "bc225304d5a3a5c9918fc5006cbc40cc",  // input
+        "27f67dc87af7ddb4b68f63fa7c2d454a",  // output
+    },
+    {
+        "TCBCMMT2 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "4ff47fda89209bda8c85f7fe80192007",  // key
+        "d5bc4891dabe48b9",                  // IV
+        "7e154b28c353adef",                  // input
+        "712b961ea9a1d0af",                  // output
+    },
+    {
+        "TCBCMMT2 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "464092cdbf736d38fb1fe6a12a94ae0e",  // key
+        "5423455f00023b01",                  // IV
+        "3f6050b74ed64416bc23d53b0469ed7a",  // input
+        "9cbe7d1b5cdd1864c3095ba810575960",  // output
+    },
+    {
+        "TCBCMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "b5cb1504802326c73df186e3e352a20de643b0d63ee30e37",  // key
+        "43f791134c5647ba",                                  // IV
+        "dcc153cef81d6f24",                                  // input
+        "92538bd8af18d3ba",                                  // output
+    },
+    {
+        "TCBCMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",  // key
+        "c2e999cb6249023c",                                  // IV
+        "c689aee38a301bb316da75db36f110b5",                  // input
+        "e9afaba5ec75ea1bbe65506655bb4ecb",                  // output
+    },
+    {
+        "TCBCMMT3 Encrypt 1 PKCS7 variant", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::PKCS7,
+        "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",  // key
+        "c2e999cb6249023c",                                  // IV
+        "c689aee38a301bb316da75db36f110b500",                // input
+        "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156",  // output
+    },
+    {
+        "TCBCMMT3 Encrypt 1 PKCS7 decrypted", KeyPurpose::DECRYPT, BlockMode::CBC,
+        PaddingMode::PKCS7,
+        "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",  // key
+        "c2e999cb6249023c",                                  // IV
+        "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156",  // input
+        "c689aee38a301bb316da75db36f110b500",                // output
+    },
+    {
+        "TCBCMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "5eb6040d46082c7aa7d06dfd08dfeac8c18364c1548c3ba1",  // key
+        "41746c7e442d3681",                                  // IV
+        "c53a7b0ec40600fe",                                  // input
+        "d4f00eb455de1034",                                  // output
+    },
+    {
+        "TCBCMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "5b1cce7c0dc1ec49130dfb4af45785ab9179e567f2c7d549",  // key
+        "3982bc02c3727d45",                                  // IV
+        "6006f10adef52991fcc777a1238bbb65",                  // input
+        "edae09288e9e3bc05746d872b48e3b29",                  // output
+    },
+};
+
+/*
+ * EncryptionOperationsTest.TripleDesTestVector
+ *
+ * Verifies that NIST (plus a few extra) test vectors produce the correct results.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesTestVector) {
+    constexpr size_t num_tests = sizeof(kTripleDesTestVectors) / sizeof(TripleDesTestVector);
+    for (auto* test = kTripleDesTestVectors; test < kTripleDesTestVectors + num_tests; ++test) {
+        SCOPED_TRACE(test->name);
+        CheckTripleDesTestVector(test->purpose, test->block_mode, test->padding_mode,
+                                 hex2str(test->key), hex2str(test->iv), hex2str(test->input),
+                                 hex2str(test->output));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcRoundTripSuccess
+ *
+ * Validates CBC mode functionality.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+    // Two-block message.
+    string message = "1234567890123456";
+    HidlBuf iv1;
+    string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv1);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    HidlBuf iv2;
+    string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv2);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(iv1, iv2);
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv1);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCallerIv
+ *
+ * Validates that 3DES keys can allow caller-specified IVs, and use them correctly.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCallerIv) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Authorization(TAG_CALLER_NONCE)
+                                             .Padding(PaddingMode::NONE)));
+    string message = "1234567890123456";
+    HidlBuf iv;
+    // Don't specify IV, should get a random one.
+    string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+    EXPECT_EQ(8U, iv.size());
+
+    string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify an IV, should also work.
+    iv = HidlBuf("abcdefgh");
+    string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, iv);
+
+    // Decrypt with correct IV.
+    plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, iv);
+    EXPECT_EQ(message, plaintext);
+
+    // Now try with wrong IV.
+    plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, HidlBuf("aaaaaaaa"));
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCallerNonceProhibited.
+ *
+ * Verifies that 3DES keys without TAG_CALLER_NONCE do not allow caller-specified IVS.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCallerNonceProhibited) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message = "12345678901234567890123456789012";
+    HidlBuf iv;
+    // Don't specify nonce, should get a random one.
+    string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+    EXPECT_EQ(8U, iv.size());
+
+    string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should fail.
+    auto input_params = AuthorizationSetBuilder()
+                            .Authorization(TAG_NONCE, HidlBuf("abcdefgh"))
+                            .BlockMode(BlockMode::CBC)
+                            .Padding(PaddingMode::NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED,
+              Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNotAuthorized
+ *
+ * Verifies that 3DES ECB-only keys do not allow CBC usage.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcNotAuthorized) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::ECB)
+                                             .Padding(PaddingMode::NONE)));
+    // Two-block message.
+    string message = "1234567890123456";
+    auto begin_params =
+        AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNoPaddingWrongInputSize
+ *
+ * Verifies that unpadded CBC operations reject inputs that are not a multiple of block size.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+    // Message is slightly shorter than two blocks.
+    string message = "123456789012345";
+
+    auto begin_params =
+        AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, "", &ciphertext));
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCbcPkcs7Padding.
+ *
+ * Verifies that PKCS7 padding works correctly in CBC mode.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    // Try various message lengths; all should work.
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        HidlBuf iv;
+        string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
+        EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, BlockMode::CBC, PaddingMode::PKCS7, iv);
+        EXPECT_EQ(message, plaintext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNoPaddingKeyWithPkcs7Padding
+ *
+ * Verifies that a key that requires PKCS7 padding cannot be used in unpadded mode.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+
+    // Try various message lengths; all should fail.
+    for (size_t i = 0; i < 32; ++i) {
+        auto begin_params =
+            AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::PKCS7);
+        EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcPkcs7PaddingCorrupted
+ *
+ * Verifies that corrupted PKCS7 padding is rejected during decryption.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    string message = "a";
+    HidlBuf iv;
+    string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
+    EXPECT_EQ(8U, ciphertext.size());
+    EXPECT_NE(ciphertext, message);
+    ++ciphertext[ciphertext.size() / 2];
+
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::CBC)
+                            .Padding(PaddingMode::PKCS7)
+                            .Authorization(TAG_NONCE, iv);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+    string plaintext;
+    size_t input_consumed;
+    EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding.
+ *
+ * Verifies that 3DES CBC works with many different input sizes.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+
+    int increment = 7;
+    string message(240, 'a');
+    AuthorizationSet input_params =
+        AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+
+    string ciphertext;
+    size_t input_consumed;
+    for (size_t i = 0; i < message.size(); i += increment)
+        EXPECT_EQ(ErrorCode::OK,
+                  Update(message.substr(i, increment), &ciphertext, &input_consumed));
+    EXPECT_EQ(ErrorCode::OK, Finish(&ciphertext));
+    EXPECT_EQ(message.size(), ciphertext.size());
+
+    // Move TAG_NONCE into input_params
+    input_params = output_params;
+    input_params.push_back(TAG_BLOCK_MODE, BlockMode::CBC);
+    input_params.push_back(TAG_PADDING, PaddingMode::NONE);
+    output_params.Clear();
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
+    string plaintext;
+    for (size_t i = 0; i < ciphertext.size(); i += increment)
+        EXPECT_EQ(ErrorCode::OK,
+                  Update(ciphertext.substr(i, increment), &plaintext, &input_consumed));
+    EXPECT_EQ(ErrorCode::OK, Finish(&plaintext));
+    EXPECT_EQ(ciphertext.size(), plaintext.size());
+    EXPECT_EQ(message, plaintext);
+}
+
+typedef KeymasterHidlTest MaxOperationsTest;
+
+/*
+ * MaxOperationsTest.TestLimitAes
+ *
+ * Verifies that the max uses per boot tag works correctly with AES keys.
+ */
+TEST_F(MaxOperationsTest, TestLimitAes) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .EcbMode()
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+    string message = "1234567890123456";
+
+    auto params = AuthorizationSetBuilder().EcbMode().Padding(PaddingMode::NONE);
+
+    EncryptMessage(message, params);
+    EncryptMessage(message, params);
+    EncryptMessage(message, params);
+
+    // Fourth time should fail.
+    EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::ENCRYPT, params));
+}
+
+/*
+ * MaxOperationsTest.TestLimitAes
+ *
+ * Verifies that the max uses per boot tag works correctly with RSA keys.
+ */
+TEST_F(MaxOperationsTest, TestLimitRsa) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .NoDigestOrPadding()
+                                             .Authorization(TAG_MAX_USES_PER_BOOT, 3)));
+
+    string message = "1234567890123456";
+
+    auto params = AuthorizationSetBuilder().NoDigestOrPadding();
+
+    SignMessage(message, params);
+    SignMessage(message, params);
+    SignMessage(message, params);
+
+    // Fourth time should fail.
+    EXPECT_EQ(ErrorCode::KEY_MAX_OPS_EXCEEDED, Begin(KeyPurpose::SIGN, params));
+}
+
+typedef KeymasterHidlTest AddEntropyTest;
+
+/*
+ * AddEntropyTest.AddEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up.  There's no way to test that entropy is
+ * actually added.
+ */
+TEST_F(AddEntropyTest, AddEntropy) {
+    EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf("foo")));
+}
+
+/*
+ * AddEntropyTest.AddEmptyEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up when given an empty buffer.
+ */
+TEST_F(AddEntropyTest, AddEmptyEntropy) {
+    EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf()));
+}
+
+/*
+ * AddEntropyTest.AddLargeEntropy
+ *
+ * Verifies that the addRngEntropy method doesn't blow up when given a largish amount of data.
+ */
+TEST_F(AddEntropyTest, AddLargeEntropy) {
+    EXPECT_EQ(ErrorCode::OK, keymaster().addRngEntropy(HidlBuf(string(2 * 1024, 'a'))));
+}
+
+typedef KeymasterHidlTest AttestationTest;
+
+/*
+ * AttestationTest.RsaAttestation
+ *
+ * Verifies that attesting to RSA keys works and generates the expected output.
+ */
+TEST_F(AttestationTest, RsaAttestation) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    ASSERT_EQ(ErrorCode::OK,
+              AttestKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                            .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+                        &cert_chain));
+    EXPECT_GE(cert_chain.size(), 2U);
+    EXPECT_TRUE(verify_chain(cert_chain));
+    EXPECT_TRUE(verify_attestation_record("challenge", "foo",                     //
+                                          key_characteristics_.softwareEnforced,  //
+                                          key_characteristics_.hardwareEnforced,  //
+                                          cert_chain[0]));
+}
+
+/*
+ * AttestationTest.RsaAttestationRequiresAppId
+ *
+ * Verifies that attesting to RSA requires app ID.
+ */
+TEST_F(AttestationTest, RsaAttestationRequiresAppId) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+              AttestKey(AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE,
+                                                                HidlBuf("challenge")),
+                        &cert_chain));
+}
+
+/*
+ * AttestationTest.EcAttestation
+ *
+ * Verifies that attesting to EC keys works and generates the expected output.
+ */
+TEST_F(AttestationTest, EcAttestation) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(EcCurve::P_256)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    ASSERT_EQ(ErrorCode::OK,
+              AttestKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                            .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+                        &cert_chain));
+    EXPECT_GE(cert_chain.size(), 2U);
+    EXPECT_TRUE(verify_chain(cert_chain));
+
+    EXPECT_TRUE(verify_attestation_record("challenge", "foo",                     //
+                                          key_characteristics_.softwareEnforced,  //
+                                          key_characteristics_.hardwareEnforced,  //
+                                          cert_chain[0]));
+}
+
+/*
+ * AttestationTest.EcAttestationRequiresAttestationAppId
+ *
+ * Verifies that attesting to EC keys requires app ID
+ */
+TEST_F(AttestationTest, EcAttestationRequiresAttestationAppId) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .EcdsaSigningKey(EcCurve::P_256)
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_INCLUDE_UNIQUE_ID)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
+              AttestKey(AuthorizationSetBuilder().Authorization(TAG_ATTESTATION_CHALLENGE,
+                                                                HidlBuf("challenge")),
+                        &cert_chain));
+}
+
+/*
+ * AttestationTest.AesAttestation
+ *
+ * Verifies that attesting to AES keys fails in the expected way.
+ */
+TEST_F(AttestationTest, AesAttestation) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .AesEncryptionKey(128)
+                                             .EcbMode()
+                                             .Padding(PaddingMode::PKCS7)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_ALGORITHM,
+              AttestKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                            .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+                        &cert_chain));
+}
+
+/*
+ * AttestationTest.HmacAttestation
+ *
+ * Verifies that attesting to HMAC keys fails in the expected way.
+ */
+TEST_F(AttestationTest, HmacAttestation) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)
+                                             .HmacKey(128)
+                                             .EcbMode()
+                                             .Digest(Digest::SHA_2_256)
+                                             .Authorization(TAG_MIN_MAC_LENGTH, 128)));
+
+    hidl_vec<hidl_vec<uint8_t>> cert_chain;
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_ALGORITHM,
+              AttestKey(AuthorizationSetBuilder()
+                            .Authorization(TAG_ATTESTATION_CHALLENGE, HidlBuf("challenge"))
+                            .Authorization(TAG_ATTESTATION_APPLICATION_ID, HidlBuf("foo")),
+                        &cert_chain));
+}
+
+typedef KeymasterHidlTest KeyDeletionTest;
+
+/**
+ * KeyDeletionTest.DeleteKey
+ *
+ * This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly
+ * valid key blob.
+ *
+ * TODO(swillden):  Update to incorporate changes in rollback resistance semantics.
+ */
+TEST_F(KeyDeletionTest, DeleteKey) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+    // Delete must work if rollback protection is implemented
+    AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+    bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+
+    if (rollback_protected) {
+        ASSERT_EQ(ErrorCode::OK, DeleteKey(true /* keep key blob */));
+    } else {
+        auto delete_result = DeleteKey(true /* keep key blob */);
+        ASSERT_TRUE(delete_result == ErrorCode::OK | delete_result == ErrorCode::UNIMPLEMENTED);
+    }
+
+    string message = "12345678901234567890123456789012";
+    AuthorizationSet begin_out_params;
+
+    if (rollback_protected) {
+        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+                  Begin(KeyPurpose::SIGN, key_blob_,
+                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+                        &begin_out_params, &op_handle_));
+    } else {
+        EXPECT_EQ(ErrorCode::OK,
+                  Begin(KeyPurpose::SIGN, key_blob_,
+                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+                        &begin_out_params, &op_handle_));
+    }
+    AbortIfNeeded();
+    key_blob_ = HidlBuf();
+}
+
+/**
+ * KeyDeletionTest.DeleteInvalidKey
+ *
+ * This test checks that the HAL excepts invalid key blobs.
+ *
+ * TODO(swillden):  Update to incorporate changes in rollback resistance semantics.
+ */
+TEST_F(KeyDeletionTest, DeleteInvalidKey) {
+    // Generate key just to check if rollback protection is implemented
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+    // Delete must work if rollback protection is implemented
+    AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+    bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+
+    // Delete the key we don't care about the result at this point.
+    DeleteKey();
+
+    // Now create an invalid key blob and delete it.
+    key_blob_ = HidlBuf("just some garbage data which is not a valid key blob");
+
+    if (rollback_protected) {
+        ASSERT_EQ(ErrorCode::OK, DeleteKey());
+    } else {
+        auto delete_result = DeleteKey();
+        ASSERT_TRUE(delete_result == ErrorCode::OK | delete_result == ErrorCode::UNIMPLEMENTED);
+    }
+}
+
+/**
+ * KeyDeletionTest.DeleteAllKeys
+ *
+ * This test is disarmed by default. To arm it use --arm_deleteAllKeys.
+ *
+ * BEWARE: This test has serious side effects. All user keys will be lost! This includes
+ * FBE/FDE encryption keys, which means that the device will not even boot until after the
+ * device has been wiped manually (e.g., fastboot flashall -w), and new FBE/FDE keys have
+ * been provisioned. Use this test only on dedicated testing devices that have no valuable
+ * credentials stored in Keystore/Keymaster.
+ *
+ * TODO(swillden):  Update to incorporate changes in rollback resistance semantics.
+ */
+TEST_F(KeyDeletionTest, DeleteAllKeys) {
+    if (!arm_deleteAllKeys) return;
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .RsaSigningKey(1024, 3)
+                                             .Digest(Digest::NONE)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+    // Delete must work if rollback protection is implemented
+    AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+    bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+
+    ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
+
+    string message = "12345678901234567890123456789012";
+    AuthorizationSet begin_out_params;
+
+    if (rollback_protected) {
+        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+                  Begin(KeyPurpose::SIGN, key_blob_,
+                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+                        &begin_out_params, &op_handle_));
+    } else {
+        EXPECT_EQ(ErrorCode::OK,
+                  Begin(KeyPurpose::SIGN, key_blob_,
+                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+                        &begin_out_params, &op_handle_));
+    }
+    AbortIfNeeded();
+    key_blob_ = HidlBuf();
+}
+
+using UpgradeKeyTest = KeymasterHidlTest;
+
+/*
+ * UpgradeKeyTest.UpgradeKey
+ *
+ * Verifies that calling upgrade key on an up-to-date key works (i.e. does nothing).
+ */
+TEST_F(UpgradeKeyTest, UpgradeKey) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .AesEncryptionKey(128)
+                                             .Padding(PaddingMode::NONE)
+                                             .Authorization(TAG_NO_AUTH_REQUIRED)));
+
+    auto result = UpgradeKey(key_blob_);
+
+    // Key doesn't need upgrading.  Should get okay, but no new key blob.
+    EXPECT_EQ(result, std::make_pair(ErrorCode::OK, HidlBuf()));
+}
+
+}  // namespace test
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+using android::hardware::keymaster::V4_0::test::KeymasterHidlEnvironment;
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(KeymasterHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    KeymasterHidlEnvironment::Instance()->init(&argc, argv);
+    for (int i = 1; i < argc; ++i) {
+        if (argv[i][0] == '-') {
+            if (std::string(argv[i]) == "--arm_deleteAllKeys") {
+                arm_deleteAllKeys = true;
+            }
+            if (std::string(argv[i]) == "--dump_attestations") {
+                dump_Attestations = true;
+            }
+        }
+    }
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
diff --git a/light/2.0/default/android.hardware.light@2.0-service.rc b/light/2.0/default/android.hardware.light@2.0-service.rc
index fcc6468..68f74c4 100644
--- a/light/2.0/default/android.hardware.light@2.0-service.rc
+++ b/light/2.0/default/android.hardware.light@2.0-service.rc
@@ -1,5 +1,5 @@
-service light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service
+service vendor.light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service
     interface android.hardware.light@2.0::ILight default
     class hal
     user system
-    group system
\ No newline at end of file
+    group system
diff --git a/media/1.0/Android.mk b/media/1.0/xml/Android.mk
similarity index 100%
rename from media/1.0/Android.mk
rename to media/1.0/xml/Android.mk
diff --git a/media/1.0/media_profiles.dtd b/media/1.0/xml/media_profiles.dtd
similarity index 100%
rename from media/1.0/media_profiles.dtd
rename to media/1.0/xml/media_profiles.dtd
diff --git a/media/bufferpool/1.0/Android.bp b/media/bufferpool/1.0/Android.bp
new file mode 100644
index 0000000..986da8a
--- /dev/null
+++ b/media/bufferpool/1.0/Android.bp
@@ -0,0 +1,26 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.media.bufferpool@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IAccessor.hal",
+        "IClientManager.hal",
+        "IConnection.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "Buffer",
+        "BufferStatus",
+        "BufferStatusMessage",
+        "ResultStatus",
+    ],
+    gen_java: false,
+}
+
diff --git a/media/bufferpool/1.0/IAccessor.hal b/media/bufferpool/1.0/IAccessor.hal
new file mode 100644
index 0000000..5b5aec0
--- /dev/null
+++ b/media/bufferpool/1.0/IAccessor.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@1.0;
+
+import IConnection;
+/**
+ * IAccessor creates IConnection which is used from IClientManager in order to
+ * use functionality of the specified buffer pool.
+ */
+interface IAccessor {
+
+    /**
+     * Registers a new client and creates IConnection to the buffer pool for
+     * the client. IConnection and FMQ are used by IClientManager in order to
+     * communicate with the buffer pool. Via FMQ IClientManager sends
+     * BufferStatusMesage(s) to the buffer pool.
+     *
+     * FMQ is used to send buffer ownership status changes to a buffer pool
+     * from a buffer pool client. A buffer pool synchronizes FMQ messages when
+     * there is a hidl request from the clients. Every client has its own
+     * connection and FMQ to communicate with the buffer pool. So sending an
+     * FMQ message on behalf of other clients is not possible.
+     *
+     * FMQ messages are sent when a buffer is acquired or released. Also, FMQ
+     * messages are sent when a buffer is transferred from a client to another
+     * client. FMQ has its own ID from a buffer pool. A client is specified
+     * with the ID.
+     *
+     * To transfer a buffer, a sender must send an FMQ message. The message
+     * must include a receiver's ID and a transaction ID. A receiver must send
+     * the transaction ID to fetch a buffer from a buffer pool. Since the
+     * sender already registered the receiver via an FMQ message, The buffer
+     * pool must verify the receiver with the transaction ID. In order to
+     * prevent faking a receiver, a connection to a buffer pool from client is
+     * made and kept private. Also part of transaction ID is a sender ID in
+     * order to prevent fake transactions from other clients. This must be
+     * verified with an FMQ message from a buffer pool.
+     *
+     * @return status The status of the call.
+     *     OK               - A connection is made successfully.
+     *     NO_MEMORY        - Memory allocation failure occurred.
+     *     ALREADY_EXISTS   - A connection was already made.
+     *     CRITICAL_ERROR   - Other errors.
+     * @return connection The IConnection have interfaces
+     *     to get shared buffers from the buffer pool.
+     * @return connectionId Id of IConnection. The Id identifies
+     *     sender and receiver in FMQ messages during buffer transfer.
+     * @return mqDesc FMQ descriptor. The descriptor can be used to
+     *     send/receive FMQ messages.
+     */
+    connect()
+        generates (ResultStatus status, IConnection connection,
+                   int64_t connectionId, fmq_sync<BufferStatusMessage> mqDesc);
+};
diff --git a/media/bufferpool/1.0/IClientManager.hal b/media/bufferpool/1.0/IClientManager.hal
new file mode 100644
index 0000000..e1e8f95
--- /dev/null
+++ b/media/bufferpool/1.0/IClientManager.hal
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@1.0;
+
+import IAccessor;
+/**
+ * IClientManager manages IConnection(s) inside a process. A locally
+ * created IConnection represents a communication node(receiver) with the
+ * specified buffer pool(IAccessor).
+ * IConnection(s) are not exposed to other processes(IClientManager).
+ * IClientManager instance must be unique within a process.
+ */
+interface IClientManager {
+
+    /**
+     * Sets up a buffer receiving communication node for the specified
+     * buffer pool. A manager must create a IConnection to the buffer
+     * pool if it does not already have a connection.
+     *
+     * @param bufferPool a buffer pool which is specified with the IAccessor.
+     *     The specified buffer pool is the owner of received buffers.
+     * @return status The status of the call.
+     *     OK               - A sender was set successfully.
+     *     NO_MEMORY        - Memory allocation failure occurred.
+     *     ALREADY_EXISTS   - A sender was registered already.
+     *     CRITICAL_ERROR   - Other errors.
+     * @return connectionId the Id of the communication node to the buffer pool.
+     *     This id is used in FMQ to notify IAccessor that a buffer has been
+     *     sent to that connection during transfers.
+     */
+    registerSender(IAccessor bufferPool) generates
+        (ResultStatus status, int64_t connectionId);
+};
diff --git a/media/bufferpool/1.0/IConnection.hal b/media/bufferpool/1.0/IConnection.hal
new file mode 100644
index 0000000..e284db2
--- /dev/null
+++ b/media/bufferpool/1.0/IConnection.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@1.0;
+
+/**
+ * A connection to a buffer pool which handles requests from a buffer pool
+ * client. The connection must be made in order to receive buffers from
+ * other buffer pool clients.
+ */
+interface IConnection {
+
+    /**
+     * Retrieves a buffer using bufferId. The method must be called from
+     * receiving side of buffer during transferring only when the specified
+     * buffer is neither cached nor used. This fails if the specified
+     * transaction is not valid.
+     *
+     * @param transactionId Unique transaction id for buffer transferring.
+     * @param bufferId Id of the buffer to be fetched.
+     * @return status The status of the call.
+     *     OK               - A buffer was fetched successfully.
+     *     NO_MEMORY        - Memory allocation failure occurred.
+     *     NOT_FOUND        - A buffer was not found due to invalidation.
+     *     CRITICAL_ERROR   - Other errors.
+     * @return buffer The actual buffer which is specified with bufferId.
+     */
+    fetch(uint64_t transactionId, uint32_t bufferId) generates
+        (ResultStatus status, Buffer buffer);
+};
diff --git a/media/bufferpool/1.0/README.md b/media/bufferpool/1.0/README.md
new file mode 100644
index 0000000..ed985d8
--- /dev/null
+++ b/media/bufferpool/1.0/README.md
@@ -0,0 +1,54 @@
+1. Overview
+
+A buffer pool enables processes to transfer buffers asynchronously.
+Without a buffer pool, a process calls a synchronous method of the other
+process and waits until the call finishes transferring a buffer. This adds
+unwanted latency due to context switching. With help from a buffer pool, a
+process can pass buffers asynchronously and reduce context switching latency.
+
+Passing an interface and a handle adds extra latency also. To mitigate the
+latency, passing IDs with local cache is used. For security concerns about
+rogue clients, FMQ is used to communicate between a buffer pool and a client
+process. FMQ is used to send buffer ownership change status from a client
+process to a buffer pool. Except FMQ, a buffer pool does not use any shared
+memory.
+
+2. FMQ
+
+FMQ is used to send buffer ownership status changes to a buffer pool from a
+buffer pool client. A buffer pool synchronizes FMQ messages when there is a
+hidl request from the clients. Every client has its own connection and FMQ
+to communicate with the buffer pool. So sending an FMQ message on behalf of
+other clients is not possible.
+
+FMQ messages are sent when a buffer is acquired or released. Also, FMQ messages
+are sent when a buffer is transferred from a client to another client. FMQ has
+its own ID from a buffer pool. A client is specified with the ID.
+
+To transfer a buffer, a sender must send an FMQ message. The message must
+include a receiver's ID and a transaction ID. A receiver must send the
+transaction ID to fetch a buffer from a buffer pool. Since the sender already
+registered the receiver via an FMQ message, The buffer pool must verify the
+receiver with the transaction ID. In order to prevent faking a receiver, a
+connection to a buffer pool from client is made and kept privately. Also part of
+transaction ID is a sender ID in order to prevent fake transactions from other
+clients. This must be verified with an FMQ message from a buffer pool.
+
+FMQ messages are defined in BufferStatus and BufferStatusMessage of 'types.hal'.
+
+3. Interfaces
+
+IConnection
+A connection to a buffer pool from a buffer pool client. The connection
+provides the functionalities to share buffers between buffer pool clients.
+The connection must be unique for each client.
+
+IAccessor
+An accessor to a buffer pool which makes a connection to the buffer pool.
+IAccesssor#connect creates an IConnection.
+
+IClientManager
+A manager of buffer pool clients and clients' connections to buffer pools. It
+sets up a process to be a receiver of buffers from a buffer pool. The manager
+is unique in a process.
+
diff --git a/media/bufferpool/1.0/types.hal b/media/bufferpool/1.0/types.hal
new file mode 100644
index 0000000..d8ab597
--- /dev/null
+++ b/media/bufferpool/1.0/types.hal
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@1.0;
+
+enum ResultStatus : int32_t {
+    OK                  = 0,
+
+    NO_MEMORY           = 1,
+    ALREADY_EXISTS      = 2,
+    NOT_FOUND           = 3,
+    CRITICAL_ERROR      = 4,
+};
+
+/**
+ * Generic buffer for fast recycling for media/stagefright.
+ *
+ * During media pipeline buffer references are created, shared and
+ * destroyed frequently. The underlying buffers are allocated on demand
+ * by a buffer pool, and are recycled to the buffer pool when they are
+ * no longer referenced by the clients.
+ *
+ * E.g. ion or gralloc buffer
+ */
+struct Buffer {
+    uint32_t id;
+    handle buffer;
+};
+
+/**
+ * Buffer ownership status for the specified client.
+ * Buffer transfer status for the specified buffer transafer transaction.
+ * BufferStatus is posted along with BufferStatusMessage from a client to
+ * the buffer pool for synchronization after status change.
+ */
+enum BufferStatus : int32_t {
+    /** No longer used by the specified client. */
+    NOT_USED            = 0,
+    /** Buffer is acquired by the specified client. */
+    USED                = 1,
+    /** Buffer is sent by the specified client. */
+    TRANSFER_TO         = 2,
+    /** Buffer transfer is acked by the receiver client. */
+    TRANSFER_FROM       = 3,
+    /** Buffer transfer is timed out by receiver client. */
+    TRANSFER_TIMEOUT    = 4,
+    /** Buffer transfer is not acked by the receiver. */
+    TRANSFER_LOST       = 5,
+    /** Buffer fetch request from the client. */
+    TRANSFER_FETCH      = 6,
+    /** Buffer transaction succeeded. */
+    TRANSFER_OK         = 7,
+    /** Buffer transaction failure. */
+    TRANSFER_ERROR      = 8,
+};
+
+/**
+ * Buffer ownership status change message. This message is
+ * sent via fmq to the buffer pool from client processes.
+ */
+struct BufferStatusMessage {
+    /**
+     * Transaction Id = (SenderId : sender local transaction Id)
+     * Transaction Id is created from sender and posted via fmq within
+     * TRANSFER_TO message.
+     */
+    uint64_t transactionId;
+    uint32_t bufferId;
+    BufferStatus newStatus;
+    /** Used by the buffer pool. not by client. */
+    int64_t connectionId;
+    /** Valid only when TRANSFER_TO is posted. */
+    int64_t targetConnectionId;
+    /**
+     * Used by the buffer pool, not by client.
+     * Monotonic timestamp in Us since fixed point in time as decided
+     * by the sender of the message
+     */
+    int64_t timestampUs;
+};
diff --git a/media/omx/1.0/vts/OWNERS b/media/omx/1.0/vts/OWNERS
new file mode 100644
index 0000000..e0e0dd1
--- /dev/null
+++ b/media/omx/1.0/vts/OWNERS
@@ -0,0 +1,7 @@
+# Media team
+pawin@google.com
+lajos@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
\ No newline at end of file
diff --git a/media/res/bbb_opus_stereo_128kbps_48000hz.info b/media/res/bbb_opus_stereo_128kbps_48000hz.info
index 12a6b99..460f98b 100644
--- a/media/res/bbb_opus_stereo_128kbps_48000hz.info
+++ b/media/res/bbb_opus_stereo_128kbps_48000hz.info
@@ -1,504 +1,499 @@
 19 128 0
 8 128 0
 8 128 0
-618 32 0
-398 32 21000
-582 32 41000
-466 32 61000
-434 32 81000
-419 32 101000
-578 32 121000
-591 32 141000
-293 32 161000
-323 32 181000
-303 32 201000
-319 32 221000
-318 32 241000
-307 32 261000
-539 32 281000
-358 32 301000
-334 32 321000
-308 32 341000
-331 32 361000
-327 32 381000
-357 32 401000
-365 32 421000
-375 32 441000
-370 32 461000
-636 32 481000
-497 32 501000
-360 32 521000
-327 32 541000
-438 32 561000
-323 32 581000
-323 32 601000
-308 32 621000
-313 32 641000
-326 32 661000
-329 32 681000
-324 32 701000
-326 32 721000
-332 32 741000
-336 32 761000
-345 32 781000
-352 32 801000
-380 32 821000
-341 32 841000
-341 32 861000
-347 32 881000
-352 32 901000
-339 32 921000
-366 32 941000
-369 32 961000
-367 32 981000
-342 32 1001000
-344 32 1021000
-339 32 1041000
-312 32 1061000
-306 32 1081000
-307 32 1101000
-308 32 1121000
-319 32 1141000
-297 32 1161000
-294 32 1181000
-298 32 1201000
-474 32 1221000
-424 32 1241000
-278 32 1261000
-290 32 1281000
-281 32 1301000
-295 32 1321000
-277 32 1341000
-305 32 1361000
-293 32 1381000
-284 32 1401000
-296 32 1421000
-298 32 1441000
-316 32 1461000
-302 32 1481000
-300 32 1501000
-283 32 1521000
-604 32 1541000
-474 32 1561000
-277 32 1581000
-285 32 1601000
-278 32 1621000
-295 32 1641000
-301 32 1661000
-317 32 1681000
-301 32 1701000
-594 32 1721000
-296 32 1741000
-374 32 1761000
-301 32 1781000
-296 32 1801000
-300 32 1821000
-285 32 1841000
-308 32 1861000
-304 32 1881000
-286 32 1901000
-294 32 1921000
-300 32 1941000
-324 32 1961000
-315 32 1981000
-326 32 2001000
-311 32 2021000
-300 32 2041000
-304 32 2061000
-307 32 2081000
-304 32 2101000
-301 32 2121000
-296 32 2141000
-299 32 2161000
-298 32 2181000
-300 32 2201000
-300 32 2221000
-303 32 2241000
-303 32 2261000
-303 32 2281000
-308 32 2301000
-304 32 2321000
-295 32 2341000
-300 32 2361000
-300 32 2381000
-293 32 2401000
-302 32 2421000
-548 32 2441000
-338 32 2461000
-311 32 2481000
-304 32 2501000
-304 32 2521000
-299 32 2541000
-298 32 2561000
-294 32 2581000
-298 32 2601000
-300 32 2621000
-301 32 2641000
-305 32 2661000
-309 32 2681000
-303 32 2701000
-313 32 2721000
-302 32 2741000
-304 32 2761000
-304 32 2781000
-304 32 2801000
-300 32 2821000
-434 32 2841000
-571 32 2861000
-386 32 2881000
-323 32 2901000
-415 32 2921000
-277 32 2941000
-401 32 2961000
-388 32 2981000
-337 32 3001000
-540 32 3021000
-516 32 3041000
-316 32 3061000
-301 32 3081000
-298 32 3101000
-302 32 3121000
-301 32 3141000
-299 32 3161000
-295 32 3181000
-281 32 3201000
-296 32 3221000
-300 32 3241000
-295 32 3261000
-308 32 3281000
-296 32 3301000
-297 32 3321000
-276 32 3341000
-281 32 3361000
-291 32 3381000
-294 32 3401000
-281 32 3421000
-277 32 3441000
-274 32 3461000
-298 32 3481000
-293 32 3501000
-279 32 3521000
-275 32 3541000
-282 32 3561000
-289 32 3581000
-300 32 3601000
-289 32 3621000
-295 32 3641000
-301 32 3661000
-306 32 3681000
-301 32 3701000
-305 32 3721000
-296 32 3741000
-296 32 3761000
-377 32 3781000
-297 32 3801000
-293 32 3821000
-290 32 3841000
-298 32 3861000
-303 32 3881000
-304 32 3901000
-316 32 3921000
-298 32 3941000
-319 32 3961000
-330 32 3981000
-316 32 4001000
-316 32 4021000
-286 32 4041000
-272 32 4061000
-257 32 4081000
-240 32 4101000
-229 32 4121000
-223 32 4141000
-225 32 4161000
-223 32 4181000
-232 32 4201000
-234 32 4221000
-224 32 4241000
-351 32 4261000
-309 32 4281000
-350 32 4301000
-437 32 4321000
-277 32 4341000
-291 32 4361000
-271 32 4381000
-266 32 4401000
-264 32 4421000
-285 32 4441000
-280 32 4461000
-276 32 4481000
-278 32 4501000
-262 32 4521000
-262 32 4541000
-246 32 4561000
-253 32 4581000
-289 32 4601000
-264 32 4621000
-285 32 4641000
-278 32 4661000
-266 32 4681000
-275 32 4701000
-264 32 4721000
-264 32 4741000
-275 32 4761000
-268 32 4781000
-262 32 4801000
-266 32 4821000
-262 32 4841000
-246 32 4861000
-284 32 4881000
-291 32 4901000
-294 32 4921000
-294 32 4941000
-294 32 4961000
-296 32 4981000
-294 32 5001000
-300 32 5021000
-293 32 5041000
-298 32 5061000
-295 32 5081000
-301 32 5101000
-301 32 5121000
-302 32 5141000
-303 32 5161000
-300 32 5181000
-301 32 5201000
-302 32 5221000
-296 32 5241000
-297 32 5261000
-300 32 5281000
-295 32 5301000
-349 32 5321000
-351 32 5341000
-333 32 5361000
-267 32 5381000
-291 32 5401000
-270 32 5421000
-258 32 5441000
-266 32 5461000
-252 32 5481000
-251 32 5501000
-323 32 5521000
-398 32 5541000
-383 32 5561000
-295 32 5581000
-260 32 5601000
-413 32 5621000
-288 32 5641000
-299 32 5661000
-277 32 5681000
-295 32 5701000
-296 32 5721000
-305 32 5741000
-300 32 5761000
-305 32 5781000
-293 32 5801000
-305 32 5821000
-455 32 5841000
-302 32 5861000
-293 32 5881000
-289 32 5901000
-283 32 5921000
-289 32 5941000
-275 32 5961000
-279 32 5981000
-626 32 6001000
-335 32 6021000
-324 32 6041000
-331 32 6061000
-334 32 6081000
-322 32 6101000
-339 32 6121000
-339 32 6141000
-329 32 6161000
-339 32 6181000
-328 32 6201000
-330 32 6221000
-312 32 6241000
-527 32 6261000
-324 32 6281000
-322 32 6301000
-313 32 6321000
-306 32 6341000
-303 32 6361000
-304 32 6381000
-311 32 6401000
-302 32 6421000
-294 32 6441000
-296 32 6461000
-293 32 6481000
-297 32 6501000
-287 32 6521000
-300 32 6541000
-324 32 6561000
-304 32 6581000
-303 32 6601000
-303 32 6621000
-324 32 6641000
-340 32 6661000
-357 32 6681000
-355 32 6701000
-349 32 6721000
-358 32 6741000
-378 32 6761000
-591 32 6781000
-525 32 6801000
-378 32 6821000
-356 32 6841000
-353 32 6861000
-347 32 6881000
-334 32 6901000
-330 32 6921000
-334 32 6941000
-352 32 6961000
-344 32 6981000
-356 32 7001000
-356 32 7021000
-351 32 7041000
-346 32 7061000
-350 32 7081000
-366 32 7101000
-504 32 7121000
-360 32 7141000
-366 32 7161000
-369 32 7181000
-363 32 7201000
-345 32 7221000
-347 32 7241000
-338 32 7261000
-332 32 7281000
-318 32 7301000
-307 32 7321000
-302 32 7341000
-308 32 7361000
-317 32 7381000
-304 32 7401000
-313 32 7421000
-314 32 7441000
-302 32 7461000
-299 32 7481000
-300 32 7501000
-295 32 7521000
-296 32 7541000
-298 32 7561000
-601 32 7581000
-489 32 7601000
-303 32 7621000
-323 32 7641000
-304 32 7661000
-328 32 7681000
-332 32 7701000
-356 32 7721000
-356 32 7741000
-340 32 7761000
-333 32 7781000
-332 32 7801000
-321 32 7821000
-455 32 7841000
-328 32 7861000
-314 32 7881000
-310 32 7901000
-300 32 7921000
-327 32 7941000
-317 32 7961000
-309 32 7981000
-305 32 8001000
-299 32 8021000
-312 32 8041000
-309 32 8061000
-300 32 8081000
-319 32 8101000
-329 32 8121000
-323 32 8141000
-332 32 8161000
-340 32 8181000
-339 32 8201000
-319 32 8221000
-323 32 8241000
-320 32 8261000
-322 32 8281000
-314 32 8301000
-310 32 8321000
-300 32 8341000
-294 32 8361000
-324 32 8381000
-325 32 8401000
-305 32 8421000
-306 32 8441000
-298 32 8461000
-302 32 8481000
-298 32 8501000
-295 32 8521000
-294 32 8541000
-295 32 8561000
-288 32 8581000
-310 32 8601000
-301 32 8621000
-401 32 8641000
-324 32 8661000
-309 32 8681000
-294 32 8701000
-306 32 8721000
-318 32 8741000
-312 32 8761000
-325 32 8781000
-352 32 8801000
-351 32 8821000
-343 32 8841000
-377 32 8861000
-409 32 8881000
-424 32 8901000
-366 32 8921000
-341 32 8941000
-330 32 8961000
-342 32 8981000
-328 32 9001000
-333 32 9021000
-334 32 9041000
-340 32 9061000
-347 32 9081000
-354 32 9101000
-342 32 9121000
-323 32 9141000
-311 32 9161000
-297 32 9181000
-286 32 9201000
-290 32 9221000
-288 32 9241000
-291 32 9261000
-439 32 9281000
-278 32 9301000
-506 32 9321000
-441 32 9341000
-333 32 9361000
-416 32 9381000
-446 32 9401000
-219 32 9421000
-353 32 9441000
-307 32 9461000
-222 32 9481000
-221 32 9501000
-235 32 9521000
-294 32 9541000
-239 32 9561000
-251 32 9581000
-259 32 9601000
-263 32 9621000
-283 32 9641000
-423 32 9661000
-296 32 9681000
-299 32 9701000
-322 32 9721000
-296 32 9741000
-489 32 9761000
-481 32 9781000
-505 32 9801000
-292 32 9821000
-390 32 9841000
-279 32 9861000
-442 32 9881000
-426 32 9901000
-408 32 9921000
-272 32 9941000
-484 32 9961000
-443 32 9981000
-440 32 10001000
+529 32 0
+329 32 13500
+349 32 33500
+336 32 53500
+383 32 73500
+359 32 93500
+344 32 113500
+343 32 133500
+332 32 153500
+320 32 173500
+319 32 193500
+323 32 213500
+320 32 233500
+328 32 253500
+340 32 273500
+318 32 293500
+319 32 313500
+335 32 333500
+511 32 353500
+395 32 373500
+327 32 393500
+479 32 413500
+332 32 433500
+320 32 453500
+321 32 473500
+310 32 493500
+310 32 513500
+310 32 533500
+326 32 553500
+330 32 573500
+318 32 593500
+309 32 613500
+304 32 633500
+298 32 653500
+294 32 673500
+300 32 693500
+314 32 713500
+304 32 733500
+307 32 753500
+321 32 773500
+333 32 793500
+335 32 813500
+306 32 833500
+315 32 853500
+320 32 873500
+315 32 893500
+308 32 913500
+320 32 933500
+311 32 953500
+311 32 973500
+313 32 993500
+314 32 1013500
+308 32 1033500
+307 32 1053500
+317 32 1073500
+328 32 1093500
+317 32 1113500
+312 32 1133500
+308 32 1153500
+315 32 1173500
+320 32 1193500
+322 32 1213500
+323 32 1233500
+322 32 1253500
+322 32 1273500
+301 32 1293500
+303 32 1313500
+308 32 1333500
+299 32 1353500
+297 32 1373500
+293 32 1393500
+295 32 1413500
+297 32 1433500
+300 32 1453500
+294 32 1473500
+299 32 1493500
+296 32 1513500
+303 32 1533500
+313 32 1553500
+306 32 1573500
+303 32 1593500
+311 32 1613500
+307 32 1633500
+310 32 1653500
+339 32 1673500
+325 32 1693500
+320 32 1713500
+315 32 1733500
+316 32 1753500
+338 32 1773500
+325 32 1793500
+325 32 1813500
+328 32 1833500
+304 32 1853500
+297 32 1873500
+322 32 1893500
+311 32 1913500
+307 32 1933500
+300 32 1953500
+301 32 1973500
+309 32 1993500
+300 32 2013500
+306 32 2033500
+305 32 2053500
+298 32 2073500
+291 32 2093500
+301 32 2113500
+300 32 2133500
+439 32 2153500
+292 32 2173500
+308 32 2193500
+305 32 2213500
+298 32 2233500
+297 32 2253500
+293 32 2273500
+408 32 2293500
+298 32 2313500
+452 32 2333500
+297 32 2353500
+303 32 2373500
+300 32 2393500
+310 32 2413500
+299 32 2433500
+306 32 2453500
+316 32 2473500
+308 32 2493500
+313 32 2513500
+309 32 2533500
+310 32 2553500
+315 32 2573500
+309 32 2593500
+317 32 2613500
+311 32 2633500
+328 32 2653500
+333 32 2673500
+326 32 2693500
+323 32 2713500
+316 32 2733500
+325 32 2753500
+316 32 2773500
+319 32 2793500
+326 32 2813500
+320 32 2833500
+328 32 2853500
+312 32 2873500
+314 32 2893500
+309 32 2913500
+306 32 2933500
+295 32 2953500
+304 32 2973500
+326 32 2993500
+291 32 3013500
+299 32 3033500
+293 32 3053500
+288 32 3073500
+294 32 3093500
+292 32 3113500
+292 32 3133500
+288 32 3153500
+308 32 3173500
+304 32 3193500
+292 32 3213500
+382 32 3233500
+381 32 3253500
+299 32 3273500
+316 32 3293500
+308 32 3313500
+301 32 3333500
+297 32 3353500
+299 32 3373500
+294 32 3393500
+295 32 3413500
+317 32 3433500
+297 32 3453500
+309 32 3473500
+313 32 3493500
+320 32 3513500
+329 32 3533500
+330 32 3553500
+324 32 3573500
+324 32 3593500
+309 32 3613500
+304 32 3633500
+313 32 3653500
+312 32 3673500
+299 32 3693500
+295 32 3713500
+301 32 3733500
+295 32 3753500
+297 32 3773500
+302 32 3793500
+298 32 3813500
+299 32 3833500
+296 32 3853500
+292 32 3873500
+307 32 3893500
+303 32 3913500
+313 32 3933500
+318 32 3953500
+313 32 3973500
+353 32 3993500
+371 32 4013500
+292 32 4033500
+300 32 4053500
+381 32 4073500
+294 32 4093500
+301 32 4113500
+305 32 4133500
+299 32 4153500
+305 32 4173500
+322 32 4193500
+315 32 4213500
+326 32 4233500
+338 32 4253500
+320 32 4273500
+319 32 4293500
+327 32 4313500
+330 32 4333500
+310 32 4353500
+303 32 4373500
+299 32 4393500
+293 32 4413500
+293 32 4433500
+294 32 4453500
+295 32 4473500
+295 32 4493500
+323 32 4513500
+309 32 4533500
+309 32 4553500
+301 32 4573500
+473 32 4593500
+291 32 4613500
+297 32 4633500
+294 32 4653500
+293 32 4673500
+304 32 4693500
+292 32 4713500
+302 32 4733500
+296 32 4753500
+298 32 4773500
+301 32 4793500
+307 32 4813500
+285 32 4833500
+294 32 4853500
+304 32 4873500
+294 32 4893500
+295 32 4913500
+325 32 4933500
+319 32 4953500
+323 32 4973500
+313 32 4993500
+303 32 5013500
+296 32 5033500
+295 32 5053500
+290 32 5073500
+297 32 5093500
+296 32 5113500
+296 32 5133500
+292 32 5153500
+295 32 5173500
+287 32 5193500
+294 32 5213500
+290 32 5233500
+297 32 5253500
+297 32 5273500
+297 32 5293500
+292 32 5313500
+297 32 5333500
+290 32 5353500
+293 32 5373500
+293 32 5393500
+291 32 5413500
+292 32 5433500
+290 32 5453500
+291 32 5473500
+296 32 5493500
+295 32 5513500
+327 32 5533500
+293 32 5553500
+291 32 5573500
+291 32 5593500
+311 32 5613500
+291 32 5633500
+294 32 5653500
+296 32 5673500
+295 32 5693500
+289 32 5713500
+295 32 5733500
+295 32 5753500
+297 32 5773500
+292 32 5793500
+297 32 5813500
+292 32 5833500
+295 32 5853500
+296 32 5873500
+295 32 5893500
+303 32 5913500
+304 32 5933500
+301 32 5953500
+307 32 5973500
+304 32 5993500
+310 32 6013500
+310 32 6033500
+305 32 6053500
+301 32 6073500
+302 32 6093500
+305 32 6113500
+298 32 6133500
+300 32 6153500
+300 32 6173500
+292 32 6193500
+297 32 6213500
+301 32 6233500
+297 32 6253500
+297 32 6273500
+298 32 6293500
+297 32 6313500
+300 32 6333500
+293 32 6353500
+293 32 6373500
+297 32 6393500
+294 32 6413500
+307 32 6433500
+302 32 6453500
+307 32 6473500
+320 32 6493500
+330 32 6513500
+333 32 6533500
+337 32 6553500
+331 32 6573500
+323 32 6593500
+312 32 6613500
+326 32 6633500
+328 32 6653500
+332 32 6673500
+333 32 6693500
+340 32 6713500
+336 32 6733500
+324 32 6753500
+312 32 6773500
+301 32 6793500
+289 32 6813500
+302 32 6833500
+296 32 6853500
+299 32 6873500
+289 32 6893500
+295 32 6913500
+299 32 6933500
+374 32 6953500
+391 32 6973500
+365 32 6993500
+340 32 7013500
+330 32 7033500
+337 32 7053500
+328 32 7073500
+329 32 7093500
+319 32 7113500
+312 32 7133500
+308 32 7153500
+304 32 7173500
+312 32 7193500
+311 32 7213500
+316 32 7233500
+299 32 7253500
+330 32 7273500
+330 32 7293500
+330 32 7313500
+342 32 7333500
+439 32 7353500
+322 32 7373500
+298 32 7393500
+293 32 7413500
+310 32 7433500
+303 32 7453500
+317 32 7473500
+453 32 7493500
+377 32 7513500
+374 32 7533500
+292 32 7553500
+295 32 7573500
+274 32 7593500
+292 32 7613500
+291 32 7633500
+367 32 7653500
+295 32 7673500
+298 32 7693500
+297 32 7713500
+301 32 7733500
+292 32 7753500
+344 32 7773500
+296 32 7793500
+297 32 7813500
+306 32 7833500
+308 32 7853500
+305 32 7873500
+313 32 7893500
+306 32 7913500
+322 32 7933500
+313 32 7953500
+305 32 7973500
+304 32 7993500
+313 32 8013500
+324 32 8033500
+312 32 8053500
+318 32 8073500
+311 32 8093500
+302 32 8113500
+305 32 8133500
+312 32 8153500
+313 32 8173500
+312 32 8193500
+335 32 8213500
+333 32 8233500
+346 32 8253500
+339 32 8273500
+337 32 8293500
+341 32 8313500
+335 32 8333500
+325 32 8353500
+324 32 8373500
+317 32 8393500
+315 32 8413500
+303 32 8433500
+317 32 8453500
+452 32 8473500
+324 32 8493500
+321 32 8513500
+335 32 8533500
+327 32 8553500
+315 32 8573500
+321 32 8593500
+319 32 8613500
+308 32 8633500
+314 32 8653500
+322 32 8673500
+328 32 8693500
+320 32 8713500
+324 32 8733500
+331 32 8753500
+330 32 8773500
+328 32 8793500
+318 32 8813500
+314 32 8833500
+318 32 8853500
+318 32 8873500
+325 32 8893500
+338 32 8913500
+341 32 8933500
+333 32 8953500
+330 32 8973500
+338 32 8993500
+333 32 9013500
+330 32 9033500
+344 32 9053500
+479 32 9073500
+473 32 9093500
+333 32 9113500
+337 32 9133500
+495 32 9153500
+353 32 9173500
+352 32 9193500
+344 32 9213500
+336 32 9233500
+324 32 9253500
+321 32 9273500
+350 32 9293500
+347 32 9313500
+343 32 9333500
+345 32 9353500
+337 32 9373500
+335 32 9393500
+333 32 9413500
+336 32 9433500
+334 32 9453500
+333 32 9473500
+331 32 9493500
+329 32 9513500
+319 32 9533500
+321 32 9553500
+316 32 9573500
+322 32 9593500
+448 32 9613500
+312 32 9633500
+306 32 9653500
+301 32 9673500
+303 32 9693500
+296 32 9713500
+300 32 9733500
+295 32 9753500
+300 32 9773500
+297 32 9793500
+300 32 9813500
+297 32 9833500
+512 32 9853500
+292 32 9873500
+468 32 9893500
diff --git a/media/res/bbb_opus_stereo_128kbps_48000hz.opus b/media/res/bbb_opus_stereo_128kbps_48000hz.opus
index 7b763b2..2b6b870 100644
--- a/media/res/bbb_opus_stereo_128kbps_48000hz.opus
+++ b/media/res/bbb_opus_stereo_128kbps_48000hz.opus
Binary files differ
diff --git a/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc b/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
index c975a18..4327a20 100644
--- a/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
+++ b/memtrack/1.0/default/android.hardware.memtrack@1.0-service.rc
@@ -1,4 +1,4 @@
-service memtrack-hal-1-0 /vendor/bin/hw/android.hardware.memtrack@1.0-service
+service vendor.memtrack-hal-1-0 /vendor/bin/hw/android.hardware.memtrack@1.0-service
     class hal
     user system
     group system
diff --git a/neuralnetworks/README b/neuralnetworks/README
new file mode 100644
index 0000000..d8c8f5d
--- /dev/null
+++ b/neuralnetworks/README
@@ -0,0 +1,2 @@
+NeuralNetworks sample driver implementation is located at
+frameworks/ml/nn/driver/sample.
diff --git a/nfc/1.0/default/android.hardware.nfc@1.0-service.rc b/nfc/1.0/default/android.hardware.nfc@1.0-service.rc
index c9b8014..3a5c776 100644
--- a/nfc/1.0/default/android.hardware.nfc@1.0-service.rc
+++ b/nfc/1.0/default/android.hardware.nfc@1.0-service.rc
@@ -1,4 +1,4 @@
-service nfc_hal_service /vendor/bin/hw/android.hardware.nfc@1.0-service
+service vendor.nfc_hal_service /vendor/bin/hw/android.hardware.nfc@1.0-service
     class hal
     user nfc
     group nfc
diff --git a/power/1.0/default/android.hardware.power@1.0-service.rc b/power/1.0/default/android.hardware.power@1.0-service.rc
index 1777e90..657c733 100644
--- a/power/1.0/default/android.hardware.power@1.0-service.rc
+++ b/power/1.0/default/android.hardware.power@1.0-service.rc
@@ -1,4 +1,4 @@
-service power-hal-1-0 /vendor/bin/hw/android.hardware.power@1.0-service
+service vendor.power-hal-1-0 /vendor/bin/hw/android.hardware.power@1.0-service
     class hal
     user system
     group system
diff --git a/power/1.2/Android.bp b/power/1.2/Android.bp
new file mode 100644
index 0000000..0eb73e7
--- /dev/null
+++ b/power/1.2/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.power@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IPower.hal",
+    ],
+    interfaces: [
+        "android.hardware.power@1.0",
+        "android.hardware.power@1.1",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "PowerHint",
+    ],
+    gen_java: true,
+}
+
diff --git a/power/1.2/IPower.hal b/power/1.2/IPower.hal
new file mode 100644
index 0000000..1c2c7b8
--- /dev/null
+++ b/power/1.2/IPower.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.power@1.2;
+
+import @1.1::IPower;
+
+interface IPower extends @1.1::IPower {
+    /**
+     * called to pass hints on power requirements which
+     * may result in adjustment of power/performance parameters of the
+     * cpufreq governor and other controls.
+     *
+     * A particular platform may choose to ignore any hint.
+     *
+     * @param hint PowerHint which is passed
+     * @param data contains additional information about the hint
+     * and is described along with the comments for each of the hints.
+     */
+    oneway powerHintAsync_1_2(PowerHint hint, int32_t data);
+};
diff --git a/power/1.2/types.hal b/power/1.2/types.hal
new file mode 100644
index 0000000..f7a6cf6
--- /dev/null
+++ b/power/1.2/types.hal
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.power@1.2;
+
+import @1.0::PowerHint;
+
+/** Power hint identifiers passed to powerHintAsync_1_2() */
+enum PowerHint : @1.0::PowerHint {
+   /**
+    * This hint indicates that audio stream is being started. Can be used
+    * for device specific optimizations during starting audio stream. The
+    * data parameter is non-zero when stream starts and zero when audio
+    * stream setup is complete.
+    */
+    AUDIO_STREAMING,
+
+   /**
+    * This hint indicates that low latency audio is active. Can be used
+    * for device specific optimizations towards low latency audio. The
+    * data parameter is non-zero when low latency audio starts and
+    * zero when ends.
+    */
+    AUDIO_LOW_LATENCY,
+
+   /**
+    * These hint indicates that camera is being launched. Can be used
+    * for device specific optimizations during camera launch. The data
+    * parameter is non-zero when camera launch starts and zero when launch
+    * is complete.
+    */
+    CAMERA_LAUNCH,
+
+   /**
+    * This hint indicates that camera stream is being started. Can be used
+    * for device specific optimizations during starting camera stream. The
+    * data parameter is non-zero when stream starts and zero when ends.
+    */
+    CAMERA_STREAMING,
+
+   /**
+    * This hint indicates that camera shot is being taken. Can be used
+    * for device specific optimizations during taking camera shot. The
+    * data parameter is non-zero when camera shot starts and zero when ends.
+    */
+    CAMERA_SHOT,
+};
diff --git a/power/1.2/vts/functional/Android.bp b/power/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..d615e85
--- /dev/null
+++ b/power/1.2/vts/functional/Android.bp
@@ -0,0 +1,26 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalPowerV1_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalPowerV1_2TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.power@1.0",
+        "android.hardware.power@1.1",
+        "android.hardware.power@1.2",
+    ],
+}
diff --git a/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp b/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp
new file mode 100644
index 0000000..5e92997
--- /dev/null
+++ b/power/1.2/vts/functional/VtsHalPowerV1_2TargetTest.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "power_hidl_hal_test"
+#include <android-base/logging.h>
+#include <android/hardware/power/1.2/IPower.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::power::V1_2::IPower;
+using ::android::hardware::power::V1_2::PowerHint;
+
+// Test environment for Power HIDL HAL.
+class PowerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static PowerHidlEnvironment* Instance() {
+        static PowerHidlEnvironment* instance = new PowerHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IPower>(); }
+};
+
+class PowerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        power = ::testing::VtsHalHidlTargetTestBase::getService<IPower>(
+            PowerHidlEnvironment::Instance()->getServiceName<IPower>());
+        ASSERT_NE(power, nullptr);
+    }
+
+    sp<IPower> power;
+};
+
+// Sanity check Power::PowerHintAsync_1_2 on good and bad inputs.
+TEST_F(PowerHidlTest, PowerHintAsync_1_2) {
+    std::vector<PowerHint> hints;
+    for (uint32_t i = static_cast<uint32_t>(PowerHint::VSYNC);
+         i <= static_cast<uint32_t>(PowerHint::CAMERA_SHOT); ++i) {
+        hints.emplace_back(static_cast<PowerHint>(i));
+    }
+    PowerHint badHint = static_cast<PowerHint>(0xFF);
+    hints.emplace_back(badHint);
+
+    Return<void> ret;
+    for (auto& hint : hints) {
+        ret = power->powerHintAsync_1_2(hint, 30000);
+        ASSERT_TRUE(ret.isOk());
+
+        ret = power->powerHintAsync_1_2(hint, 0);
+        ASSERT_TRUE(ret.isOk());
+    }
+
+    // Turning these hints on in different orders triggers different code paths,
+    // so iterate over possible orderings.
+    std::vector<PowerHint> hints2 = {PowerHint::AUDIO_STREAMING, PowerHint::CAMERA_LAUNCH,
+                                     PowerHint::CAMERA_STREAMING, PowerHint::CAMERA_SHOT};
+    auto compareHints = [](PowerHint l, PowerHint r) {
+        return static_cast<uint32_t>(l) < static_cast<uint32_t>(r);
+    };
+    std::sort(hints2.begin(), hints2.end(), compareHints);
+    do {
+        for (auto iter = hints2.begin(); iter != hints2.end(); iter++) {
+            ret = power->powerHintAsync_1_2(*iter, 0);
+            ASSERT_TRUE(ret.isOk());
+        }
+        for (auto iter = hints2.begin(); iter != hints2.end(); iter++) {
+            ret = power->powerHintAsync_1_2(*iter, 30000);
+            ASSERT_TRUE(ret.isOk());
+        }
+    } while (std::next_permutation(hints2.begin(), hints2.end(), compareHints));
+}
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(PowerHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    PowerHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp
index e6c8934..566a516 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp
@@ -316,4 +316,4 @@
              RadioError::INVALID_SIM_STATE, RadioError::MODEM_ERR, RadioError::NO_MEMORY,
              RadioError::PASSWORD_INCORRECT, RadioError::SIM_ABSENT, RadioError::SYSTEM_ERR}));
     }
-}
\ No newline at end of file
+}
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
index e5268f6..cb0a730 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
@@ -864,4 +864,4 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp->rspInfo.error,
                                      {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
     }
-}
\ No newline at end of file
+}
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_test.cpp b/radio/1.0/vts/functional/sap_hidl_hal_test.cpp
index 7720505..fc8cb2a 100644
--- a/radio/1.0/vts/functional/sap_hidl_hal_test.cpp
+++ b/radio/1.0/vts/functional/sap_hidl_hal_test.cpp
@@ -34,19 +34,19 @@
     std::unique_lock<std::mutex> lock(mtx);
     count++;
     cv.notify_one();
-    }
+}
 
-    std::cv_status SapHidlTest::wait() {
-        std::unique_lock<std::mutex> lock(mtx);
+std::cv_status SapHidlTest::wait() {
+    std::unique_lock<std::mutex> lock(mtx);
 
-        std::cv_status status = std::cv_status::no_timeout;
-        auto now = std::chrono::system_clock::now();
-        while (count == 0) {
-            status = cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
-            if (status == std::cv_status::timeout) {
-                return status;
-            }
+    std::cv_status status = std::cv_status::no_timeout;
+    auto now = std::chrono::system_clock::now();
+    while (count == 0) {
+        status = cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) {
+            return status;
         }
-        count--;
-        return status;
-    }
\ No newline at end of file
+    }
+    count--;
+    return status;
+}
\ No newline at end of file
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_test.cpp b/radio/1.1/vts/functional/radio_hidl_hal_test.cpp
index 488da2d..773d165 100644
--- a/radio/1.1/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.1/vts/functional/radio_hidl_hal_test.cpp
@@ -20,6 +20,11 @@
     radio_v1_1 =
         ::testing::VtsHalHidlTargetTestBase::getService<::android::hardware::radio::V1_1::IRadio>(
             hidl_string(RADIO_SERVICE_NAME));
+    if (radio_v1_1 == NULL) {
+        sleep(60);
+        radio_v1_1 = ::testing::VtsHalHidlTargetTestBase::getService<
+            ::android::hardware::radio::V1_1::IRadio>(hidl_string(RADIO_SERVICE_NAME));
+    }
     ASSERT_NE(nullptr, radio_v1_1.get());
 
     radioRsp_v1_1 = new (std::nothrow) RadioResponse_v1_1(*this);
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_test.cpp b/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
index 4f05eff..c1ab88b 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
@@ -19,6 +19,11 @@
 void RadioHidlTest_v1_2::SetUp() {
     radio_v1_2 = ::testing::VtsHalHidlTargetTestBase::getService<V1_2::IRadio>(
         hidl_string(RADIO_SERVICE_NAME));
+    if (radio_v1_2 == NULL) {
+        sleep(60);
+        radio_v1_2 = ::testing::VtsHalHidlTargetTestBase::getService<V1_2::IRadio>(
+            hidl_string(RADIO_SERVICE_NAME));
+    }
     ASSERT_NE(nullptr, radio_v1_2.get());
 
     radioRsp_v1_2 = new (std::nothrow) RadioResponse_v1_2(*this);
diff --git a/renderscript/1.0/default/Android.bp b/renderscript/1.0/default/Android.bp
index b996969..d5d6d8d 100644
--- a/renderscript/1.0/default/Android.bp
+++ b/renderscript/1.0/default/Android.bp
@@ -12,7 +12,7 @@
     ],
     shared_libs: [
         "libdl",
-        "liblog",
+        "libbase",
         "libhidlbase",
         "libhidltransport",
         "libutils",
diff --git a/renderscript/1.0/default/Context.cpp b/renderscript/1.0/default/Context.cpp
index fbfc652..f5b70c9 100644
--- a/renderscript/1.0/default/Context.cpp
+++ b/renderscript/1.0/default/Context.cpp
@@ -1,5 +1,3 @@
-#define LOG_TAG "android.hardware.renderscript@1.0-impl"
-
 #include "Context.h"
 #include "Device.h"
 
diff --git a/renderscript/1.0/default/Device.cpp b/renderscript/1.0/default/Device.cpp
index a2b950d..8fda3ff 100644
--- a/renderscript/1.0/default/Device.cpp
+++ b/renderscript/1.0/default/Device.cpp
@@ -1,6 +1,7 @@
 #include "Context.h"
 #include "Device.h"
 
+#include <android-base/logging.h>
 #include <android/dlext.h>
 #include <dlfcn.h>
 
@@ -54,12 +55,18 @@
                 .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = rsNamespace,
             };
             handle = android_dlopen_ext(filename, RTLD_LAZY | RTLD_LOCAL, &dlextinfo);
+            if (handle == nullptr) {
+                LOG(WARNING) << "android_dlopen_ext(" << filename << ") failed: " << dlerror();
+            }
         }
     }
     if (handle == nullptr) {
         // if there is no "rs" namespace (in case when this HAL impl is loaded
         // into a vendor process), then use the plain dlopen.
         handle = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
+        if (handle == nullptr) {
+            LOG(FATAL) << "dlopen(" << filename << ") failed: " << dlerror();
+        }
     }
 
     dispatchTable dispatchHal = {
diff --git a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
index 3e5d0f8..b54842d 100644
--- a/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
+++ b/sensors/1.0/default/android.hardware.sensors@1.0-service.rc
@@ -1,4 +1,4 @@
-service sensors-hal-1-0 /vendor/bin/hw/android.hardware.sensors@1.0-service
+service vendor.sensors-hal-1-0 /vendor/bin/hw/android.hardware.sensors@1.0-service
     class hal
     user system
     group system wakelock
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index fb8d22e..0ea400e 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -24,7 +24,7 @@
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
-        "android.hardware.sensors@1.0"
-    ]
+        "android.hardware.sensors@1.0",
+    ],
 }
 
diff --git a/soundtrigger/2.0/default/Android.bp b/soundtrigger/2.0/default/Android.bp
new file mode 100644
index 0000000..cc20f91
--- /dev/null
+++ b/soundtrigger/2.0/default/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "android.hardware.soundtrigger@2.0-core",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "SoundTriggerHalImpl.cpp",
+    ],
+
+    export_include_dirs: ["."],
+
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "libhardware",
+        "android.hardware.soundtrigger@2.0",
+        "android.hardware.audio.common@2.0",
+    ],
+
+    header_libs: [
+        "libaudio_system_headers",
+        "libhardware_headers",
+    ],
+}
diff --git a/soundtrigger/2.0/default/Android.mk b/soundtrigger/2.0/default/Android.mk
index 9262858..835a020 100644
--- a/soundtrigger/2.0/default/Android.mk
+++ b/soundtrigger/2.0/default/Android.mk
@@ -18,23 +18,20 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := android.hardware.soundtrigger@2.0-impl
-LOCAL_PROPRIETARY_MODULE := true
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_SRC_FILES := \
-    SoundTriggerHalImpl.cpp
+    FetchISoundTriggerHw.cpp
 
 LOCAL_CFLAGS := -Wall -Werror
 
 LOCAL_SHARED_LIBRARIES := \
-        libhidlbase \
-        libhidltransport \
-        liblog \
-        libutils \
         libhardware \
+        libutils \
         android.hardware.soundtrigger@2.0 \
-        android.hardware.audio.common@2.0
+        android.hardware.soundtrigger@2.0-core
 
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+LOCAL_C_INCLUDE_DIRS := $(LOCAL_PATH)
 
 ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
 LOCAL_MULTILIB := 32
diff --git a/soundtrigger/2.0/default/FetchISoundTriggerHw.cpp b/soundtrigger/2.0/default/FetchISoundTriggerHw.cpp
new file mode 100644
index 0000000..bd99221
--- /dev/null
+++ b/soundtrigger/2.0/default/FetchISoundTriggerHw.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SoundTriggerHalImpl.h"
+
+extern "C" ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(
+    const char* /* name */) {
+    return (new ::android::hardware::soundtrigger::V2_0::implementation::SoundTriggerHalImpl())
+        ->getInterface();
+}
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
index 996519b..612772c 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
@@ -17,9 +17,8 @@
 #define LOG_TAG "SoundTriggerHalImpl"
 //#define LOG_NDEBUG 0
 
-#include <android/log.h>
 #include "SoundTriggerHalImpl.h"
-
+#include <android/log.h>
 
 namespace android {
 namespace hardware {
@@ -28,64 +27,45 @@
 namespace implementation {
 
 // static
-void SoundTriggerHalImpl::soundModelCallback(struct sound_trigger_model_event *halEvent,
-                                               void *cookie)
-{
+void SoundTriggerHalImpl::soundModelCallback(struct sound_trigger_model_event* halEvent,
+                                             void* cookie) {
     if (halEvent == NULL) {
         ALOGW("soundModelCallback called with NULL event");
         return;
     }
     sp<SoundModelClient> client =
-            wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote();
+        wp<SoundModelClient>(static_cast<SoundModelClient*>(cookie)).promote();
     if (client == 0) {
         ALOGW("soundModelCallback called on stale client");
         return;
     }
-    if (halEvent->model != client->mHalHandle) {
+    if (halEvent->model != client->getHalHandle()) {
         ALOGW("soundModelCallback call with wrong handle %d on client with handle %d",
-              (int)halEvent->model, (int)client->mHalHandle);
+              (int)halEvent->model, (int)client->getHalHandle());
         return;
     }
 
-    ISoundTriggerHwCallback::ModelEvent event;
-    convertSoundModelEventFromHal(&event, halEvent);
-    event.model = client->mId;
-
-    client->mCallback->soundModelCallback(event, client->mCookie);
+    client->soundModelCallback(halEvent);
 }
 
 // static
-void SoundTriggerHalImpl::recognitionCallback(struct sound_trigger_recognition_event *halEvent,
-                                               void *cookie)
-{
+void SoundTriggerHalImpl::recognitionCallback(struct sound_trigger_recognition_event* halEvent,
+                                              void* cookie) {
     if (halEvent == NULL) {
         ALOGW("recognitionCallback call NULL event");
         return;
     }
     sp<SoundModelClient> client =
-            wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote();
+        wp<SoundModelClient>(static_cast<SoundModelClient*>(cookie)).promote();
     if (client == 0) {
         ALOGW("soundModelCallback called on stale client");
         return;
     }
 
-    ISoundTriggerHwCallback::RecognitionEvent *event = convertRecognitionEventFromHal(halEvent);
-    event->model = client->mId;
-    if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
-        client->mCallback->phraseRecognitionCallback(
-                *(reinterpret_cast<ISoundTriggerHwCallback::PhraseRecognitionEvent *>(event)),
-                client->mCookie);
-    } else {
-        client->mCallback->recognitionCallback(*event, client->mCookie);
-    }
-    delete event;
+    client->recognitionCallback(halEvent);
 }
 
-
-
-// Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
-Return<void> SoundTriggerHalImpl::getProperties(getProperties_cb _hidl_cb)
-{
+Return<void> SoundTriggerHalImpl::getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb) {
     ALOGV("getProperties() mHwDevice %p", mHwDevice);
     int ret;
     struct sound_trigger_properties halProperties;
@@ -100,8 +80,8 @@
 
     convertPropertiesFromHal(&properties, &halProperties);
 
-    ALOGV("getProperties implementor %s recognitionModes %08x",
-          properties.implementor.c_str(), properties.recognitionModes);
+    ALOGV("getProperties implementor %s recognitionModes %08x", properties.implementor.c_str(),
+          properties.recognitionModes);
 
 exit:
     _hidl_cb(ret, properties);
@@ -109,14 +89,9 @@
 }
 
 int SoundTriggerHalImpl::doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
-                                                 const sp<ISoundTriggerHwCallback>& callback,
-                                                 ISoundTriggerHwCallback::CallbackCookie cookie,
-                                                 uint32_t *modelId)
-{
+                                          sp<SoundModelClient> client) {
     int32_t ret = 0;
-    struct sound_trigger_sound_model *halSoundModel;
-    *modelId = 0;
-    sp<SoundModelClient> client;
+    struct sound_trigger_sound_model* halSoundModel;
 
     ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size());
 
@@ -131,19 +106,9 @@
         goto exit;
     }
 
-    {
-        AutoMutex lock(mLock);
-        do {
-            *modelId = nextUniqueId();
-        } while (mClients.valueFor(*modelId) != 0 && *modelId != 0);
-    }
-    LOG_ALWAYS_FATAL_IF(*modelId == 0,
-                        "wrap around in sound model IDs, num loaded models %zu", mClients.size());
-
-    client = new SoundModelClient(*modelId, callback, cookie);
-
-    ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback,
-                                          client.get(), &client->mHalHandle);
+    sound_model_handle_t halHandle;
+    ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback, client.get(),
+                                      &halHandle);
 
     free(halSoundModel);
 
@@ -151,9 +116,10 @@
         goto exit;
     }
 
+    client->setHalHandle(halHandle);
     {
         AutoMutex lock(mLock);
-        mClients.add(*modelId, client);
+        mClients.add(client->getId(), client);
     }
 
 exit:
@@ -163,31 +129,23 @@
 Return<void> SoundTriggerHalImpl::loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
                                                  const sp<ISoundTriggerHwCallback>& callback,
                                                  ISoundTriggerHwCallback::CallbackCookie cookie,
-                                                 loadSoundModel_cb _hidl_cb)
-{
-    uint32_t modelId = 0;
-    int32_t ret = doLoadSoundModel(soundModel, callback, cookie, &modelId);
-
-    _hidl_cb(ret, modelId);
+                                                 ISoundTriggerHw::loadSoundModel_cb _hidl_cb) {
+    sp<SoundModelClient> client = new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+    _hidl_cb(doLoadSoundModel(soundModel, client), client->getId());
     return Void();
 }
 
 Return<void> SoundTriggerHalImpl::loadPhraseSoundModel(
-                                            const ISoundTriggerHw::PhraseSoundModel& soundModel,
-                                            const sp<ISoundTriggerHwCallback>& callback,
-                                            ISoundTriggerHwCallback::CallbackCookie cookie,
-                                            ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb)
-{
-    uint32_t modelId = 0;
-    int32_t ret = doLoadSoundModel((const ISoundTriggerHw::SoundModel&)soundModel,
-                                   callback, cookie, &modelId);
-
-    _hidl_cb(ret, modelId);
+    const ISoundTriggerHw::PhraseSoundModel& soundModel,
+    const sp<ISoundTriggerHwCallback>& callback, ISoundTriggerHwCallback::CallbackCookie cookie,
+    ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) {
+    sp<SoundModelClient> client = new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+    _hidl_cb(doLoadSoundModel((const ISoundTriggerHw::SoundModel&)soundModel, client),
+             client->getId());
     return Void();
 }
 
-Return<int32_t> SoundTriggerHalImpl::unloadSoundModel(SoundModelHandle modelHandle)
-{
+Return<int32_t> SoundTriggerHalImpl::unloadSoundModel(SoundModelHandle modelHandle) {
     int32_t ret;
     sp<SoundModelClient> client;
 
@@ -205,7 +163,7 @@
         }
     }
 
-    ret = mHwDevice->unload_sound_model(mHwDevice, client->mHalHandle);
+    ret = mHwDevice->unload_sound_model(mHwDevice, client->getHalHandle());
 
     mClients.removeItem(modelHandle);
 
@@ -213,14 +171,11 @@
     return ret;
 }
 
-Return<int32_t> SoundTriggerHalImpl::startRecognition(SoundModelHandle modelHandle,
-                                           const ISoundTriggerHw::RecognitionConfig& config,
-                                           const sp<ISoundTriggerHwCallback>& callback __unused,
-                                           ISoundTriggerHwCallback::CallbackCookie cookie __unused)
-{
+Return<int32_t> SoundTriggerHalImpl::startRecognition(
+    SoundModelHandle modelHandle, const ISoundTriggerHw::RecognitionConfig& config) {
     int32_t ret;
     sp<SoundModelClient> client;
-    struct sound_trigger_recognition_config *halConfig;
+    struct sound_trigger_recognition_config* halConfig;
 
     if (mHwDevice == NULL) {
         ret = -ENODEV;
@@ -236,15 +191,14 @@
         }
     }
 
-
     halConfig = convertRecognitionConfigToHal(&config);
 
     if (halConfig == NULL) {
         ret = -EINVAL;
         goto exit;
     }
-    ret = mHwDevice->start_recognition(mHwDevice, client->mHalHandle, halConfig,
-                                 recognitionCallback, client.get());
+    ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig,
+                                       recognitionCallback, client.get());
 
     free(halConfig);
 
@@ -252,8 +206,7 @@
     return ret;
 }
 
-Return<int32_t> SoundTriggerHalImpl::stopRecognition(SoundModelHandle modelHandle)
-{
+Return<int32_t> SoundTriggerHalImpl::stopRecognition(SoundModelHandle modelHandle) {
     int32_t ret;
     sp<SoundModelClient> client;
     if (mHwDevice == NULL) {
@@ -270,14 +223,13 @@
         }
     }
 
-    ret = mHwDevice->stop_recognition(mHwDevice, client->mHalHandle);
+    ret = mHwDevice->stop_recognition(mHwDevice, client->getHalHandle());
 
 exit:
     return ret;
 }
 
-Return<int32_t> SoundTriggerHalImpl::stopAllRecognitions()
-{
+Return<int32_t> SoundTriggerHalImpl::stopAllRecognitions() {
     int32_t ret;
     if (mHwDevice == NULL) {
         ret = -ENODEV;
@@ -285,7 +237,7 @@
     }
 
     if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 &&
-            mHwDevice->stop_all_recognitions) {
+        mHwDevice->stop_all_recognitions) {
         ret = mHwDevice->stop_all_recognitions(mHwDevice);
     } else {
         ret = -ENOSYS;
@@ -295,19 +247,16 @@
 }
 
 SoundTriggerHalImpl::SoundTriggerHalImpl()
-    : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1)
-{
-}
+    : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) {}
 
-void SoundTriggerHalImpl::onFirstRef()
-{
-    const hw_module_t *mod;
+void SoundTriggerHalImpl::onFirstRef() {
+    const hw_module_t* mod;
     int rc;
 
     rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
     if (rc != 0) {
-        ALOGE("couldn't load sound trigger module %s.%s (%s)",
-              SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+        ALOGE("couldn't load sound trigger module %s.%s (%s)", SOUND_TRIGGER_HARDWARE_MODULE_ID,
+              mModuleName, strerror(-rc));
         return;
     }
     rc = sound_trigger_hw_device_open(mod, &mHwDevice);
@@ -318,7 +267,7 @@
         return;
     }
     if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 ||
-            mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
+        mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
         ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
         sound_trigger_hw_device_close(mHwDevice);
         mHwDevice = NULL;
@@ -328,22 +277,27 @@
     ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice);
 }
 
-SoundTriggerHalImpl::~SoundTriggerHalImpl()
-{
+SoundTriggerHalImpl::~SoundTriggerHalImpl() {
     if (mHwDevice != NULL) {
         sound_trigger_hw_device_close(mHwDevice);
     }
 }
 
-uint32_t SoundTriggerHalImpl::nextUniqueId()
-{
-    return (uint32_t) atomic_fetch_add_explicit(&mNextModelId,
-                (uint_fast32_t) 1, memory_order_acq_rel);
+uint32_t SoundTriggerHalImpl::nextUniqueModelId() {
+    uint32_t modelId = 0;
+    {
+        AutoMutex lock(mLock);
+        do {
+            modelId =
+                atomic_fetch_add_explicit(&mNextModelId, (uint_fast32_t)1, memory_order_acq_rel);
+        } while (mClients.valueFor(modelId) != 0 && modelId != 0);
+    }
+    LOG_ALWAYS_FATAL_IF(modelId == 0, "wrap around in sound model IDs, num loaded models %zu",
+                        mClients.size());
+    return modelId;
 }
 
-void SoundTriggerHalImpl::convertUuidFromHal(Uuid *uuid,
-                                             const sound_trigger_uuid_t *halUuid)
-{
+void SoundTriggerHalImpl::convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid) {
     uuid->timeLow = halUuid->timeLow;
     uuid->timeMid = halUuid->timeMid;
     uuid->versionAndTimeHigh = halUuid->timeHiAndVersion;
@@ -351,9 +305,7 @@
     memcpy(&uuid->node[0], &halUuid->node[0], 6);
 }
 
-void SoundTriggerHalImpl::convertUuidToHal(sound_trigger_uuid_t *halUuid,
-                                           const Uuid *uuid)
-{
+void SoundTriggerHalImpl::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid) {
     halUuid->timeLow = uuid->timeLow;
     halUuid->timeMid = uuid->timeMid;
     halUuid->timeHiAndVersion = uuid->versionAndTimeHigh;
@@ -362,9 +314,7 @@
 }
 
 void SoundTriggerHalImpl::convertPropertiesFromHal(
-        ISoundTriggerHw::Properties *properties,
-        const struct sound_trigger_properties *halProperties)
-{
+    ISoundTriggerHw::Properties* properties, const struct sound_trigger_properties* halProperties) {
     properties->implementor = halProperties->implementor;
     properties->description = halProperties->description;
     properties->version = halProperties->version;
@@ -378,54 +328,49 @@
     properties->concurrentCapture = halProperties->concurrent_capture;
     properties->triggerInEvent = halProperties->trigger_in_event;
     properties->powerConsumptionMw = halProperties->power_consumption_mw;
-
 }
 
-void SoundTriggerHalImpl::convertTriggerPhraseToHal(
-        struct sound_trigger_phrase *halTriggerPhrase,
-        const ISoundTriggerHw::Phrase *triggerPhrase)
-{
+void SoundTriggerHalImpl::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+                                                    const ISoundTriggerHw::Phrase* triggerPhrase) {
     halTriggerPhrase->id = triggerPhrase->id;
     halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes;
     unsigned int i;
-    for (i = 0; i < triggerPhrase->users.size(); i++) {
+
+    halTriggerPhrase->num_users =
+        std::min((int)triggerPhrase->users.size(), SOUND_TRIGGER_MAX_USERS);
+    for (i = 0; i < halTriggerPhrase->num_users; i++) {
         halTriggerPhrase->users[i] = triggerPhrase->users[i];
     }
-    halTriggerPhrase->num_users = i;
 
-    strlcpy(halTriggerPhrase->locale,
-            triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
-    strlcpy(halTriggerPhrase->text,
-            triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+    strlcpy(halTriggerPhrase->locale, triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
+    strlcpy(halTriggerPhrase->text, triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
 }
 
-struct sound_trigger_sound_model *SoundTriggerHalImpl::convertSoundModelToHal(
-        const ISoundTriggerHw::SoundModel *soundModel)
-{
-    struct sound_trigger_sound_model *halModel = NULL;
+struct sound_trigger_sound_model* SoundTriggerHalImpl::convertSoundModelToHal(
+    const ISoundTriggerHw::SoundModel* soundModel) {
+    struct sound_trigger_sound_model* halModel = NULL;
     if (soundModel->type == SoundModelType::KEYPHRASE) {
         size_t allocSize =
-                sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
-        struct sound_trigger_phrase_sound_model *halKeyPhraseModel =
-                static_cast<struct sound_trigger_phrase_sound_model *>(malloc(allocSize));
+            sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
+        struct sound_trigger_phrase_sound_model* halKeyPhraseModel =
+            static_cast<struct sound_trigger_phrase_sound_model*>(malloc(allocSize));
         LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL,
-                        "malloc failed for size %zu in convertSoundModelToHal PHRASE", allocSize);
+                            "malloc failed for size %zu in convertSoundModelToHal PHRASE",
+                            allocSize);
 
-        const ISoundTriggerHw::PhraseSoundModel *keyPhraseModel =
-                reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel *>(soundModel);
+        const ISoundTriggerHw::PhraseSoundModel* keyPhraseModel =
+            reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel*>(soundModel);
 
         size_t i;
         for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
-            convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i],
-                                      &keyPhraseModel->phrases[i]);
+            convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], &keyPhraseModel->phrases[i]);
         }
         halKeyPhraseModel->num_phrases = (unsigned int)i;
-        halModel = reinterpret_cast<struct sound_trigger_sound_model *>(halKeyPhraseModel);
+        halModel = reinterpret_cast<struct sound_trigger_sound_model*>(halKeyPhraseModel);
         halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model);
     } else {
-        size_t allocSize =
-                sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
-        halModel = static_cast<struct sound_trigger_sound_model *>(malloc(allocSize));
+        size_t allocSize = sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
+        halModel = static_cast<struct sound_trigger_sound_model*>(malloc(allocSize));
         LOG_ALWAYS_FATAL_IF(halModel == NULL,
                             "malloc failed for size %zu in convertSoundModelToHal GENERIC",
                             allocSize);
@@ -436,17 +381,15 @@
     convertUuidToHal(&halModel->uuid, &soundModel->uuid);
     convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid);
     halModel->data_size = soundModel->data.size();
-    uint8_t *dst = reinterpret_cast<uint8_t *>(halModel) + halModel->data_offset;
-    const uint8_t *src = reinterpret_cast<const uint8_t *>(&soundModel->data[0]);
+    uint8_t* dst = reinterpret_cast<uint8_t*>(halModel) + halModel->data_offset;
+    const uint8_t* src = reinterpret_cast<const uint8_t*>(&soundModel->data[0]);
     memcpy(dst, src, soundModel->data.size());
 
     return halModel;
 }
 
 void SoundTriggerHalImpl::convertPhraseRecognitionExtraToHal(
-        struct sound_trigger_phrase_recognition_extra *halExtra,
-        const PhraseRecognitionExtra *extra)
-{
+    struct sound_trigger_phrase_recognition_extra* halExtra, const PhraseRecognitionExtra* extra) {
     halExtra->id = extra->id;
     halExtra->recognition_modes = extra->recognitionModes;
     halExtra->confidence_level = extra->confidenceLevel;
@@ -459,16 +402,14 @@
     halExtra->num_levels = i;
 }
 
-struct sound_trigger_recognition_config *SoundTriggerHalImpl::convertRecognitionConfigToHal(
-        const ISoundTriggerHw::RecognitionConfig *config)
-{
+struct sound_trigger_recognition_config* SoundTriggerHalImpl::convertRecognitionConfigToHal(
+    const ISoundTriggerHw::RecognitionConfig* config) {
     size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size();
-    struct sound_trigger_recognition_config *halConfig =
-            static_cast<struct sound_trigger_recognition_config *>(malloc(allocSize));
+    struct sound_trigger_recognition_config* halConfig =
+        static_cast<struct sound_trigger_recognition_config*>(malloc(allocSize));
 
     LOG_ALWAYS_FATAL_IF(halConfig == NULL,
-                        "malloc failed for size %zu in convertRecognitionConfigToHal",
-                        allocSize);
+                        "malloc failed for size %zu in convertRecognitionConfigToHal", allocSize);
 
     halConfig->capture_handle = (audio_io_handle_t)config->captureHandle;
     halConfig->capture_device = (audio_devices_t)config->captureDevice;
@@ -476,57 +417,43 @@
 
     unsigned int i;
     for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
-        convertPhraseRecognitionExtraToHal(&halConfig->phrases[i],
-                                  &config->phrases[i]);
+        convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], &config->phrases[i]);
     }
     halConfig->num_phrases = i;
 
     halConfig->data_offset = sizeof(struct sound_trigger_recognition_config);
     halConfig->data_size = config->data.size();
-    uint8_t *dst = reinterpret_cast<uint8_t *>(halConfig) + halConfig->data_offset;
-    const uint8_t *src = reinterpret_cast<const uint8_t *>(&config->data[0]);
+    uint8_t* dst = reinterpret_cast<uint8_t*>(halConfig) + halConfig->data_offset;
+    const uint8_t* src = reinterpret_cast<const uint8_t*>(&config->data[0]);
     memcpy(dst, src, config->data.size());
     return halConfig;
 }
 
 // static
-void SoundTriggerHalImpl::convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event,
-                                                const struct sound_trigger_model_event *halEvent)
-{
+void SoundTriggerHalImpl::convertSoundModelEventFromHal(
+    ISoundTriggerHwCallback::ModelEvent* event, const struct sound_trigger_model_event* halEvent) {
     event->status = (ISoundTriggerHwCallback::SoundModelStatus)halEvent->status;
     // event->model to be remapped by called
     event->data.setToExternal(
-            const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset,
-            halEvent->data_size);
+        const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + halEvent->data_offset,
+        halEvent->data_size);
 }
 
 // static
-ISoundTriggerHwCallback::RecognitionEvent *SoundTriggerHalImpl::convertRecognitionEventFromHal(
-                                            const struct sound_trigger_recognition_event *halEvent)
-{
-    ISoundTriggerHwCallback::RecognitionEvent * event;
-
-    if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
-        const struct sound_trigger_phrase_recognition_event *halPhraseEvent =
-                reinterpret_cast<const struct sound_trigger_phrase_recognition_event *>(halEvent);
-        ISoundTriggerHwCallback::PhraseRecognitionEvent *phraseEvent =
-                new ISoundTriggerHwCallback::PhraseRecognitionEvent();
-
-        PhraseRecognitionExtra *phraseExtras =
-                new PhraseRecognitionExtra[halPhraseEvent->num_phrases];
-        for (unsigned int i = 0; i < halPhraseEvent->num_phrases; i++) {
-            convertPhraseRecognitionExtraFromHal(&phraseExtras[i],
-                                                 &halPhraseEvent->phrase_extras[i]);
-        }
-        phraseEvent->phraseExtras.setToExternal(phraseExtras, halPhraseEvent->num_phrases);
-        // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
-        phraseEvent->phraseExtras.resize(halPhraseEvent->num_phrases);
-        delete[] phraseExtras;
-        event = reinterpret_cast<ISoundTriggerHwCallback::RecognitionEvent *>(phraseEvent);
-    } else {
-        event = new ISoundTriggerHwCallback::RecognitionEvent();
+void SoundTriggerHalImpl::convertPhaseRecognitionEventFromHal(
+    ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+    const struct sound_trigger_phrase_recognition_event* halEvent) {
+    event->phraseExtras.resize(halEvent->num_phrases);
+    for (unsigned int i = 0; i < halEvent->num_phrases; i++) {
+        convertPhraseRecognitionExtraFromHal(&event->phraseExtras[i], &halEvent->phrase_extras[i]);
     }
+    convertRecognitionEventFromHal(&event->common, &halEvent->common);
+}
 
+// static
+void SoundTriggerHalImpl::convertRecognitionEventFromHal(
+    ISoundTriggerHwCallback::RecognitionEvent* event,
+    const struct sound_trigger_recognition_event* halEvent) {
     event->status = static_cast<ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status);
     event->type = static_cast<SoundModelType>(halEvent->type);
     // event->model to be remapped by called
@@ -537,45 +464,53 @@
     event->triggerInData = halEvent->trigger_in_data;
     event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate;
     event->audioConfig.channelMask =
-            (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
+        (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
     event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format;
     event->data.setToExternal(
-            const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset,
-            halEvent->data_size);
-
-    return event;
+        const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + halEvent->data_offset,
+        halEvent->data_size);
 }
 
 // static
 void SoundTriggerHalImpl::convertPhraseRecognitionExtraFromHal(
-        PhraseRecognitionExtra *extra,
-        const struct sound_trigger_phrase_recognition_extra *halExtra)
-{
+    PhraseRecognitionExtra* extra, const struct sound_trigger_phrase_recognition_extra* halExtra) {
     extra->id = halExtra->id;
     extra->recognitionModes = halExtra->recognition_modes;
     extra->confidenceLevel = halExtra->confidence_level;
 
-    ConfidenceLevel *levels =
-            new ConfidenceLevel[halExtra->num_levels];
-    for (unsigned int i = 0; i < halExtra->num_levels; i++) {
-        levels[i].userId = halExtra->levels[i].user_id;
-        levels[i].levelPercent = halExtra->levels[i].level;
-    }
-    extra->levels.setToExternal(levels, halExtra->num_levels);
-    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
     extra->levels.resize(halExtra->num_levels);
-    delete[] levels;
+    for (unsigned int i = 0; i < halExtra->num_levels; i++) {
+        extra->levels[i].userId = halExtra->levels[i].user_id;
+        extra->levels[i].levelPercent = halExtra->levels[i].level;
+    }
 }
 
-ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char* /* name */)
-{
-    return new SoundTriggerHalImpl();
+void SoundTriggerHalImpl::SoundModelClient_2_0::recognitionCallback(
+    struct sound_trigger_recognition_event* halEvent) {
+    if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+        ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+        convertPhaseRecognitionEventFromHal(
+            &event, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+        event.common.model = mId;
+        mCallback->phraseRecognitionCallback(event, mCookie);
+    } else {
+        ISoundTriggerHwCallback::RecognitionEvent event;
+        convertRecognitionEventFromHal(&event, halEvent);
+        event.model = mId;
+        mCallback->recognitionCallback(event, mCookie);
+    }
 }
-} // namespace implementation
+
+void SoundTriggerHalImpl::SoundModelClient_2_0::soundModelCallback(
+    struct sound_trigger_model_event* halEvent) {
+    ISoundTriggerHwCallback::ModelEvent event;
+    convertSoundModelEventFromHal(&event, halEvent);
+    event.model = mId;
+    mCallback->soundModelCallback(event, mCookie);
+}
+
+}  // namespace implementation
 }  // namespace V2_0
 }  // namespace soundtrigger
 }  // namespace hardware
 }  // namespace android
-
-
-
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.h b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
index 4769590..5a9f0e1 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.h
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
@@ -19,12 +19,12 @@
 
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
+#include <hardware/sound_trigger.h>
 #include <hidl/Status.h>
 #include <stdatomic.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
 #include <system/sound_trigger.h>
-#include <hardware/sound_trigger.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
 
 namespace android {
 namespace hardware {
@@ -35,96 +35,144 @@
 using ::android::hardware::audio::common::V2_0::Uuid;
 using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
 
+class SoundTriggerHalImpl : public RefBase {
+   public:
+    SoundTriggerHalImpl();
+    ISoundTriggerHw* getInterface() { return new TrampolineSoundTriggerHw_2_0(this); }
 
-class SoundTriggerHalImpl : public ISoundTriggerHw {
-public:
-        SoundTriggerHalImpl();
+   protected:
+    class SoundModelClient : public RefBase {
+       public:
+        SoundModelClient(uint32_t id, ISoundTriggerHwCallback::CallbackCookie cookie)
+            : mId(id), mCookie(cookie) {}
+        virtual ~SoundModelClient() {}
+
+        uint32_t getId() const { return mId; }
+        sound_model_handle_t getHalHandle() const { return mHalHandle; }
+        void setHalHandle(sound_model_handle_t handle) { mHalHandle = handle; }
+
+        virtual void recognitionCallback(struct sound_trigger_recognition_event* halEvent) = 0;
+        virtual void soundModelCallback(struct sound_trigger_model_event* halEvent) = 0;
+
+       protected:
+        const uint32_t mId;
+        sound_model_handle_t mHalHandle;
+        ISoundTriggerHwCallback::CallbackCookie mCookie;
+    };
+
+    static void convertPhaseRecognitionEventFromHal(
+        ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+        const struct sound_trigger_phrase_recognition_event* halEvent);
+    static void convertRecognitionEventFromHal(
+        ISoundTriggerHwCallback::RecognitionEvent* event,
+        const struct sound_trigger_recognition_event* halEvent);
+    static void convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent* event,
+                                              const struct sound_trigger_model_event* halEvent);
+
+    virtual ~SoundTriggerHalImpl();
+
+    Return<void> getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb);
+    Return<void> loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
+                                const sp<ISoundTriggerHwCallback>& callback,
+                                ISoundTriggerHwCallback::CallbackCookie cookie,
+                                ISoundTriggerHw::loadSoundModel_cb _hidl_cb);
+    Return<void> loadPhraseSoundModel(const ISoundTriggerHw::PhraseSoundModel& soundModel,
+                                      const sp<ISoundTriggerHwCallback>& callback,
+                                      ISoundTriggerHwCallback::CallbackCookie cookie,
+                                      ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb);
+    Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle);
+    Return<int32_t> startRecognition(SoundModelHandle modelHandle,
+                                     const ISoundTriggerHw::RecognitionConfig& config);
+    Return<int32_t> stopRecognition(SoundModelHandle modelHandle);
+    Return<int32_t> stopAllRecognitions();
+
+    uint32_t nextUniqueModelId();
+    int doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
+                         sp<SoundModelClient> client);
+
+    // RefBase
+    void onFirstRef() override;
+
+   private:
+    struct TrampolineSoundTriggerHw_2_0 : public ISoundTriggerHw {
+        explicit TrampolineSoundTriggerHw_2_0(sp<SoundTriggerHalImpl> impl) : mImpl(impl) {}
 
         // Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
-        Return<void> getProperties(getProperties_cb _hidl_cb)  override;
+        Return<void> getProperties(getProperties_cb _hidl_cb) override {
+            return mImpl->getProperties(_hidl_cb);
+        }
         Return<void> loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
                                     const sp<ISoundTriggerHwCallback>& callback,
                                     ISoundTriggerHwCallback::CallbackCookie cookie,
-                                    loadSoundModel_cb _hidl_cb)  override;
+                                    loadSoundModel_cb _hidl_cb) override {
+            return mImpl->loadSoundModel(soundModel, callback, cookie, _hidl_cb);
+        }
         Return<void> loadPhraseSoundModel(const ISoundTriggerHw::PhraseSoundModel& soundModel,
-                                    const sp<ISoundTriggerHwCallback>& callback,
-                                    ISoundTriggerHwCallback::CallbackCookie cookie,
-                                    loadPhraseSoundModel_cb _hidl_cb)  override;
+                                          const sp<ISoundTriggerHwCallback>& callback,
+                                          ISoundTriggerHwCallback::CallbackCookie cookie,
+                                          loadPhraseSoundModel_cb _hidl_cb) override {
+            return mImpl->loadPhraseSoundModel(soundModel, callback, cookie, _hidl_cb);
+        }
+        Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle) override {
+            return mImpl->unloadSoundModel(modelHandle);
+        }
+        Return<int32_t> startRecognition(
+            SoundModelHandle modelHandle, const ISoundTriggerHw::RecognitionConfig& config,
+            const sp<ISoundTriggerHwCallback>& /*callback*/,
+            ISoundTriggerHwCallback::CallbackCookie /*cookie*/) override {
+            return mImpl->startRecognition(modelHandle, config);
+        }
+        Return<int32_t> stopRecognition(SoundModelHandle modelHandle) override {
+            return mImpl->stopRecognition(modelHandle);
+        }
+        Return<int32_t> stopAllRecognitions() override { return mImpl->stopAllRecognitions(); }
 
-        Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle)  override;
-        Return<int32_t> startRecognition(SoundModelHandle modelHandle,
-                                      const ISoundTriggerHw::RecognitionConfig& config,
-                                      const sp<ISoundTriggerHwCallback>& callback,
-                                      ISoundTriggerHwCallback::CallbackCookie cookie)  override;
-        Return<int32_t> stopRecognition(SoundModelHandle modelHandle)  override;
-        Return<int32_t> stopAllRecognitions()  override;
+       private:
+        sp<SoundTriggerHalImpl> mImpl;
+    };
 
-        // RefBase
-        virtual     void        onFirstRef();
+    class SoundModelClient_2_0 : public SoundModelClient {
+       public:
+        SoundModelClient_2_0(uint32_t id, ISoundTriggerHwCallback::CallbackCookie cookie,
+                             sp<ISoundTriggerHwCallback> callback)
+            : SoundModelClient(id, cookie), mCallback(callback) {}
 
-        static void soundModelCallback(struct sound_trigger_model_event *halEvent,
-                                       void *cookie);
-        static void recognitionCallback(struct sound_trigger_recognition_event *halEvent,
-                                        void *cookie);
+        void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+        void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
 
-private:
+       private:
+        sp<ISoundTriggerHwCallback> mCallback;
+    };
 
-        class SoundModelClient : public RefBase {
-        public:
-            SoundModelClient(uint32_t id, sp<ISoundTriggerHwCallback> callback,
-                             ISoundTriggerHwCallback::CallbackCookie cookie)
-                : mId(id), mCallback(callback), mCookie(cookie) {}
-            virtual ~SoundModelClient() {}
+    void convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid);
+    void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid);
+    void convertPropertiesFromHal(ISoundTriggerHw::Properties* properties,
+                                  const struct sound_trigger_properties* halProperties);
+    void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+                                   const ISoundTriggerHw::Phrase* triggerPhrase);
+    // returned HAL sound model must be freed by caller
+    struct sound_trigger_sound_model* convertSoundModelToHal(
+        const ISoundTriggerHw::SoundModel* soundModel);
+    void convertPhraseRecognitionExtraToHal(struct sound_trigger_phrase_recognition_extra* halExtra,
+                                            const PhraseRecognitionExtra* extra);
+    // returned recognition config must be freed by caller
+    struct sound_trigger_recognition_config* convertRecognitionConfigToHal(
+        const ISoundTriggerHw::RecognitionConfig* config);
 
-            uint32_t mId;
-            sound_model_handle_t mHalHandle;
-            sp<ISoundTriggerHwCallback> mCallback;
-            ISoundTriggerHwCallback::CallbackCookie mCookie;
-        };
+    static void convertPhraseRecognitionExtraFromHal(
+        PhraseRecognitionExtra* extra,
+        const struct sound_trigger_phrase_recognition_extra* halExtra);
 
-        uint32_t nextUniqueId();
-        void convertUuidFromHal(Uuid *uuid,
-                                const sound_trigger_uuid_t *halUuid);
-        void convertUuidToHal(sound_trigger_uuid_t *halUuid,
-                              const Uuid *uuid);
-        void convertPropertiesFromHal(ISoundTriggerHw::Properties *properties,
-                                      const struct sound_trigger_properties *halProperties);
-        void convertTriggerPhraseToHal(struct sound_trigger_phrase *halTriggerPhrase,
-                                       const ISoundTriggerHw::Phrase *triggerPhrase);
-        // returned HAL sound model must be freed by caller
-        struct sound_trigger_sound_model *convertSoundModelToHal(
-                    const ISoundTriggerHw::SoundModel *soundModel);
-        void convertPhraseRecognitionExtraToHal(
-                struct sound_trigger_phrase_recognition_extra *halExtra,
-                const PhraseRecognitionExtra *extra);
-        // returned recognition config must be freed by caller
-        struct sound_trigger_recognition_config *convertRecognitionConfigToHal(
-                const ISoundTriggerHw::RecognitionConfig *config);
+    static void soundModelCallback(struct sound_trigger_model_event* halEvent, void* cookie);
+    static void recognitionCallback(struct sound_trigger_recognition_event* halEvent, void* cookie);
 
-
-        static void convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event,
-                                            const struct sound_trigger_model_event *halEvent);
-        static ISoundTriggerHwCallback::RecognitionEvent *convertRecognitionEventFromHal(
-                                            const struct sound_trigger_recognition_event *halEvent);
-        static void convertPhraseRecognitionExtraFromHal(PhraseRecognitionExtra *extra,
-                                    const struct sound_trigger_phrase_recognition_extra *halExtra);
-
-        int doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
-                             const sp<ISoundTriggerHwCallback>& callback,
-                             ISoundTriggerHwCallback::CallbackCookie cookie,
-                             uint32_t *modelId);
-
-        virtual             ~SoundTriggerHalImpl();
-
-        const char *                                        mModuleName;
-        struct sound_trigger_hw_device*                     mHwDevice;
-        volatile atomic_uint_fast32_t                       mNextModelId;
-        DefaultKeyedVector<int32_t, sp<SoundModelClient> >  mClients;
-        Mutex                                               mLock;
+    const char* mModuleName;
+    struct sound_trigger_hw_device* mHwDevice;
+    volatile atomic_uint_fast32_t mNextModelId;
+    DefaultKeyedVector<int32_t, sp<SoundModelClient> > mClients;
+    Mutex mLock;
 };
 
-extern "C" ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char *name);
-
 }  // namespace implementation
 }  // namespace V2_0
 }  // namespace soundtrigger
@@ -132,4 +180,3 @@
 }  // namespace android
 
 #endif  // ANDROID_HARDWARE_SOUNDTRIGGER_V2_0_IMPLEMENTATION_H
-
diff --git a/soundtrigger/2.1/Android.bp b/soundtrigger/2.1/Android.bp
new file mode 100644
index 0000000..ed1ec3d
--- /dev/null
+++ b/soundtrigger/2.1/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.soundtrigger@2.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "ISoundTriggerHw.hal",
+        "ISoundTriggerHwCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@2.0",
+        "android.hardware.soundtrigger@2.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
+
diff --git a/soundtrigger/2.1/ISoundTriggerHw.hal b/soundtrigger/2.1/ISoundTriggerHw.hal
new file mode 100644
index 0000000..a9796d8
--- /dev/null
+++ b/soundtrigger/2.1/ISoundTriggerHw.hal
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.soundtrigger@2.1;
+
+import @2.0::ISoundTriggerHw;
+import @2.0::ISoundTriggerHwCallback.CallbackCookie;
+import @2.0::SoundModelHandle;
+
+import ISoundTriggerHwCallback;
+
+/**
+ * SoundTrigger HAL interface. Used for hardware recognition of hotwords.
+ */
+interface ISoundTriggerHw extends @2.0::ISoundTriggerHw {
+
+    /**
+     * Base sound model descriptor. This struct is the header of a larger block
+     * passed to loadSoundModel_2_1() and contains the binary data of the
+     * sound model.
+     */
+    struct SoundModel {
+        /** Sound model header. Any data contained in the 'header.data' field
+         * is ignored */
+        @2.0::ISoundTriggerHw.SoundModel header;
+        /** Opaque data transparent to Android framework */
+        memory data;
+    };
+
+    /**
+     * Specialized sound model for key phrase detection.
+     * Proprietary representation of key phrases in binary data must match
+     * information indicated by phrases field.
+     */
+    struct PhraseSoundModel {
+        /** Common part of sound model descriptor */
+        SoundModel  common;
+        /** List of descriptors for key phrases supported by this sound model */
+        vec<Phrase> phrases;
+    };
+
+    /**
+     * Configuration for sound trigger capture session passed to
+     * startRecognition_2_1() method.
+     */
+    struct RecognitionConfig {
+        /** Configuration header. Any data contained in the 'header.data' field
+         * is ignored */
+        @2.0::ISoundTriggerHw.RecognitionConfig header;
+        /** Opaque capture configuration data transparent to the framework */
+        memory data;
+    };
+
+    /**
+     * Load a sound model. Once loaded, recognition of this model can be
+     * started and stopped. Only one active recognition per model at a time.
+     * The SoundTrigger service must handle concurrent recognition requests by
+     * different users/applications on the same model.
+     * The implementation returns a unique handle used by other functions
+     * (unloadSoundModel(), startRecognition*(), etc...
+     *
+     * Must have the exact same semantics as loadSoundModel from
+     * ISoundTriggerHw@2.0 except that the SoundModel uses shared memory
+     * instead of data.
+     *
+     * @param soundModel A SoundModel structure describing the sound model
+     *     to load.
+     * @param callback The callback interface on which the soundmodelCallback*()
+     *     method must be called upon completion.
+     * @param cookie The value of the cookie argument passed to the completion
+     *     callback. This unique context information is assigned and
+     *     used only by the framework.
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid sound model (e.g 0 data size),
+     *     -ENOSYS in case of invalid operation (e.g max number of models
+     *             exceeded),
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     * @return modelHandle A unique handle assigned by the HAL for use by the
+     *     framework when controlling activity for this sound model.
+     */
+    @callflow(next={"startRecognition_2_1", "unloadSoundModel"})
+    loadSoundModel_2_1(SoundModel soundModel,
+                   ISoundTriggerHwCallback callback,
+                   CallbackCookie cookie)
+            generates (int32_t retval, SoundModelHandle modelHandle);
+
+    /**
+     * Load a key phrase sound model. Once loaded, recognition of this model can
+     * be started and stopped. Only one active recognition per model at a time.
+     * The SoundTrigger service must handle concurrent recognition requests by
+     * different users/applications on the same model.
+     * The implementation returns a unique handle used by other functions
+     * (unloadSoundModel(), startRecognition*(), etc...
+     *
+     * Must have the exact same semantics as loadPhraseSoundModel from
+     * ISoundTriggerHw@2.0 except that the PhraseSoundModel uses shared memory
+     * instead of data.
+     *
+     * @param soundModel A PhraseSoundModel structure describing the sound model
+     *     to load.
+     * @param callback The callback interface on which the soundmodelCallback*()
+     *     method must be called upon completion.
+     * @param cookie The value of the cookie argument passed to the completion
+     *     callback. This unique context information is assigned and
+     *     used only by the framework.
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid sound model (e.g 0 data size),
+     *     -ENOSYS in case of invalid operation (e.g max number of models
+     *             exceeded),
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     * @return modelHandle A unique handle assigned by the HAL for use by the
+     *     framework when controlling activity for this sound model.
+     */
+    @callflow(next={"startRecognition_2_1", "unloadSoundModel"})
+    loadPhraseSoundModel_2_1(PhraseSoundModel soundModel,
+                   ISoundTriggerHwCallback callback,
+                   CallbackCookie cookie)
+            generates (int32_t retval, SoundModelHandle modelHandle);
+
+    /**
+     * Start recognition on a given model. Only one recognition active
+     * at a time per model. Once recognition succeeds of fails, the callback
+     * is called.
+     *
+     * Must have the exact same semantics as startRecognition from
+     * ISoundTriggerHw@2.0 except that the RecognitionConfig uses shared memory
+     * instead of data.
+     *
+     * @param modelHandle the handle of the sound model to use for recognition
+     * @param config A RecognitionConfig structure containing attributes of the
+     *     recognition to perform
+     * @param callback The callback interface on which the recognitionCallback()
+     *     method must be called upon recognition.
+     * @param cookie The value of the cookie argument passed to the recognition
+     *     callback. This unique context information is assigned and
+     *     used only by the framework.
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid recognition attributes,
+     *     -ENOSYS in case of invalid model handle,
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     */
+    @callflow(next={"stopRecognition", "stopAllRecognitions"})
+    startRecognition_2_1(SoundModelHandle modelHandle,
+                     RecognitionConfig config,
+                     ISoundTriggerHwCallback callback,
+                     CallbackCookie cookie)
+            generates (int32_t retval);
+};
diff --git a/soundtrigger/2.1/ISoundTriggerHwCallback.hal b/soundtrigger/2.1/ISoundTriggerHwCallback.hal
new file mode 100644
index 0000000..42e851b
--- /dev/null
+++ b/soundtrigger/2.1/ISoundTriggerHwCallback.hal
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.soundtrigger@2.1;
+
+import @2.0::ISoundTriggerHwCallback;
+import @2.0::PhraseRecognitionExtra;
+
+/**
+ * SoundTrigger HAL Callback interface. Obtained during SoundTrigger setup.
+ */
+@hidl_callback
+interface ISoundTriggerHwCallback extends @2.0::ISoundTriggerHwCallback {
+
+    /**
+     * Generic recognition event sent via recognition callback.
+     */
+    struct RecognitionEvent {
+        /** Event header. Any data contained in the 'header.data' field
+         * is ignored */
+        @2.0::ISoundTriggerHwCallback.RecognitionEvent header;
+        /** Opaque event data */
+        memory data;
+    };
+
+    /**
+     * Specialized recognition event for key phrase recognitions.
+     */
+    struct PhraseRecognitionEvent {
+        /** Common part of the recognition event */
+        RecognitionEvent common;
+        /** List of descriptors for each recognized key phrase */
+        vec<PhraseRecognitionExtra> phraseExtras;
+    };
+
+    /**
+     * Event sent via load sound model callback.
+     */
+    struct ModelEvent {
+        /** Event header. Any data contained in the 'header.data' field
+         * is ignored */
+        @2.0::ISoundTriggerHwCallback.ModelEvent header;
+        /** Opaque event data, passed transparently by the framework */
+        memory data;
+    };
+
+    /**
+     * Callback method called by the HAL when the sound recognition triggers.
+     *
+     * @param event A RecognitionEvent structure containing detailed results
+     *     of the recognition triggered
+     * @param cookie The cookie passed by the framework when recognition was
+     *     started (see ISoundtriggerHw.startRecognition*())
+     */
+    recognitionCallback_2_1(RecognitionEvent event, CallbackCookie cookie);
+
+    /**
+     * Callback method called by the HAL when the sound recognition triggers
+     * for a key phrase sound model.
+     *
+     * @param event A RecognitionEvent structure containing detailed results
+     *     of the recognition triggered
+     * @param cookie The cookie passed by the framework when recognition was
+     *     started (see ISoundtriggerHw.startRecognition*())
+     */
+    phraseRecognitionCallback_2_1(PhraseRecognitionEvent event,
+                                  CallbackCookie cookie);
+
+    /**
+     * Callback method called by the HAL when the sound model loading completes.
+     *
+     * @param event A ModelEvent structure containing detailed results of the
+     *     model loading operation
+     * @param cookie The cookie passed by the framework when loading was
+     *     initiated (see ISoundtriggerHw.loadSoundModel*())
+     */
+    soundModelCallback_2_1(ModelEvent event, CallbackCookie cookie);
+};
diff --git a/soundtrigger/2.1/default/Android.mk b/soundtrigger/2.1/default/Android.mk
new file mode 100644
index 0000000..5851d63
--- /dev/null
+++ b/soundtrigger/2.1/default/Android.mk
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.soundtrigger@2.1-impl
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+    SoundTriggerHw.cpp
+
+LOCAL_CFLAGS := -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+        libhardware \
+        libhidlbase \
+        libhidlmemory \
+        libhidltransport \
+        liblog \
+        libutils \
+        android.hardware.soundtrigger@2.1 \
+        android.hardware.soundtrigger@2.0 \
+        android.hardware.soundtrigger@2.0-core \
+        android.hidl.allocator@1.0 \
+        android.hidl.memory@1.0
+
+LOCAL_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
+LOCAL_MULTILIB := 32
+else
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/soundtrigger/2.1/default/SoundTriggerHw.cpp b/soundtrigger/2.1/default/SoundTriggerHw.cpp
new file mode 100644
index 0000000..246d2bc
--- /dev/null
+++ b/soundtrigger/2.1/default/SoundTriggerHw.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SoundTriggerHw"
+
+#include "SoundTriggerHw.h"
+
+#include <utility>
+
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/log.h>
+#include <hidlmemory/mapping.h>
+
+using android::hardware::hidl_memory;
+using android::hidl::allocator::V1_0::IAllocator;
+using android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_1 {
+namespace implementation {
+
+namespace {
+
+// Backs up by the vector with the contents of shared memory.
+// It is assumed that the passed hidl_vector is empty, so it's
+// not cleared if the memory is a null object.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> memoryAsVector(const hidl_memory& m, hidl_vec<uint8_t>* vec) {
+    sp<IMemory> memory;
+    if (m.size() == 0) {
+        return std::make_pair(true, memory);
+    }
+    memory = mapMemory(m);
+    if (memory != nullptr) {
+        memory->read();
+        vec->setToExternal(static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())),
+                           memory->getSize());
+        return std::make_pair(true, memory);
+    }
+    ALOGE("%s: Could not map HIDL memory to IMemory", __func__);
+    return std::make_pair(false, memory);
+}
+
+// Moves the data from the vector into allocated shared memory,
+// emptying the vector.
+// It is assumed that the passed hidl_memory is a null object, so it's
+// not reset if the vector is empty.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> moveVectorToMemory(hidl_vec<uint8_t>* v, hidl_memory* mem) {
+    sp<IMemory> memory;
+    if (v->size() == 0) {
+        return std::make_pair(true, memory);
+    }
+    sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+    if (ashmem == 0) {
+        ALOGE("Failed to retrieve ashmem allocator service");
+        return std::make_pair(false, memory);
+    }
+    bool success = false;
+    Return<void> r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) {
+        success = s;
+        if (success) *mem = m;
+    });
+    if (r.isOk() && success) {
+        memory = hardware::mapMemory(*mem);
+        if (memory != 0) {
+            memory->update();
+            memcpy(memory->getPointer(), v->data(), v->size());
+            memory->commit();
+            v->resize(0);
+            return std::make_pair(true, memory);
+        } else {
+            ALOGE("Failed to map allocated ashmem");
+        }
+    } else {
+        ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size());
+    }
+    return std::make_pair(false, memory);
+}
+
+}  // namespace
+
+Return<void> SoundTriggerHw::loadSoundModel_2_1(
+    const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+    const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+    V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb) {
+    // It is assumed that legacy data vector is empty, thus making copy is cheap.
+    V2_0::ISoundTriggerHw::SoundModel soundModel_2_0(soundModel.header);
+    auto result = memoryAsVector(soundModel.data, &soundModel_2_0.data);
+    if (result.first) {
+        sp<SoundModelClient> client =
+            new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+        _hidl_cb(doLoadSoundModel(soundModel_2_0, client), client->getId());
+        return Void();
+    }
+    _hidl_cb(-ENOMEM, 0);
+    return Void();
+}
+
+Return<void> SoundTriggerHw::loadPhraseSoundModel_2_1(
+    const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+    const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+    V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb) {
+    V2_0::ISoundTriggerHw::PhraseSoundModel soundModel_2_0;
+    // It is assumed that legacy data vector is empty, thus making copy is cheap.
+    soundModel_2_0.common = soundModel.common.header;
+    // Avoid copying phrases data.
+    soundModel_2_0.phrases.setToExternal(
+        const_cast<V2_0::ISoundTriggerHw::Phrase*>(soundModel.phrases.data()),
+        soundModel.phrases.size());
+    auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data);
+    if (result.first) {
+        sp<SoundModelClient> client =
+            new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+        _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel_2_0, client),
+                 client->getId());
+        return Void();
+    }
+    _hidl_cb(-ENOMEM, 0);
+    return Void();
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition_2_1(
+    int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config) {
+    // It is assumed that legacy data vector is empty, thus making copy is cheap.
+    V2_0::ISoundTriggerHw::RecognitionConfig config_2_0(config.header);
+    auto result = memoryAsVector(config.data, &config_2_0.data);
+    return result.first ? startRecognition(modelHandle, config_2_0) : Return<int32_t>(-ENOMEM);
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::recognitionCallback(
+    struct sound_trigger_recognition_event* halEvent) {
+    if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+        V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0;
+        convertPhaseRecognitionEventFromHal(
+            &event_2_0, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+        event_2_0.common.model = mId;
+        V2_1::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+        event.phraseExtras.setToExternal(event_2_0.phraseExtras.data(),
+                                         event_2_0.phraseExtras.size());
+        auto result = moveVectorToMemory(&event_2_0.common.data, &event.common.data);
+        if (result.first) {
+            // The data vector is now empty, thus copying is cheap.
+            event.common.header = event_2_0.common;
+            mCallback->phraseRecognitionCallback_2_1(event, mCookie);
+        }
+    } else {
+        V2_1::ISoundTriggerHwCallback::RecognitionEvent event;
+        convertRecognitionEventFromHal(&event.header, halEvent);
+        event.header.model = mId;
+        auto result = moveVectorToMemory(&event.header.data, &event.data);
+        if (result.first) {
+            mCallback->recognitionCallback_2_1(event, mCookie);
+        }
+    }
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::soundModelCallback(
+    struct sound_trigger_model_event* halEvent) {
+    V2_1::ISoundTriggerHwCallback::ModelEvent event;
+    convertSoundModelEventFromHal(&event.header, halEvent);
+    event.header.model = mId;
+    auto result = moveVectorToMemory(&event.header.data, &event.data);
+    if (result.first) {
+        mCallback->soundModelCallback_2_1(event, mCookie);
+    }
+}
+
+ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) {
+    return (new SoundTriggerHw())->getInterface();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace soundtrigger
+}  // namespace hardware
+}  // namespace android
diff --git a/soundtrigger/2.1/default/SoundTriggerHw.h b/soundtrigger/2.1/default/SoundTriggerHw.h
new file mode 100644
index 0000000..a5515eb
--- /dev/null
+++ b/soundtrigger/2.1/default/SoundTriggerHw.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_V2_1_SOUNDTRIGGERHW_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_1_SOUNDTRIGGERHW_H
+
+#include <SoundTriggerHalImpl.h>
+#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct SoundTriggerHw : public V2_0::implementation::SoundTriggerHalImpl {
+    SoundTriggerHw() = default;
+    ISoundTriggerHw* getInterface() { return new TrampolineSoundTriggerHw_2_1(this); }
+
+   protected:
+    virtual ~SoundTriggerHw() = default;
+
+    Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+                                    const sp<V2_1::ISoundTriggerHwCallback>& callback,
+                                    int32_t cookie,
+                                    V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb);
+    Return<void> loadPhraseSoundModel_2_1(
+        const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+        const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+        V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb);
+    Return<int32_t> startRecognition_2_1(int32_t modelHandle,
+                                         const V2_1::ISoundTriggerHw::RecognitionConfig& config);
+
+   private:
+    struct TrampolineSoundTriggerHw_2_1 : public ISoundTriggerHw {
+        explicit TrampolineSoundTriggerHw_2_1(sp<SoundTriggerHw> impl) : mImpl(impl) {}
+
+        // Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
+        Return<void> getProperties(getProperties_cb _hidl_cb) override {
+            return mImpl->getProperties(_hidl_cb);
+        }
+        Return<void> loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+                                    const sp<V2_0::ISoundTriggerHwCallback>& callback,
+                                    int32_t cookie, loadSoundModel_cb _hidl_cb) override {
+            return mImpl->loadSoundModel(soundModel, callback, cookie, _hidl_cb);
+        }
+        Return<void> loadPhraseSoundModel(const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel,
+                                          const sp<V2_0::ISoundTriggerHwCallback>& callback,
+                                          int32_t cookie,
+                                          loadPhraseSoundModel_cb _hidl_cb) override {
+            return mImpl->loadPhraseSoundModel(soundModel, callback, cookie, _hidl_cb);
+        }
+        Return<int32_t> unloadSoundModel(V2_0::SoundModelHandle modelHandle) override {
+            return mImpl->unloadSoundModel(modelHandle);
+        }
+        Return<int32_t> startRecognition(int32_t modelHandle,
+                                         const V2_0::ISoundTriggerHw::RecognitionConfig& config,
+                                         const sp<V2_0::ISoundTriggerHwCallback>& /*callback*/,
+                                         int32_t /*cookie*/) override {
+            return mImpl->startRecognition(modelHandle, config);
+        }
+        Return<int32_t> stopRecognition(V2_0::SoundModelHandle modelHandle) override {
+            return mImpl->stopRecognition(modelHandle);
+        }
+        Return<int32_t> stopAllRecognitions() override { return mImpl->stopAllRecognitions(); }
+
+        // Methods from V2_1::ISoundTriggerHw follow.
+        Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+                                        const sp<V2_1::ISoundTriggerHwCallback>& callback,
+                                        int32_t cookie, loadSoundModel_2_1_cb _hidl_cb) override {
+            return mImpl->loadSoundModel_2_1(soundModel, callback, cookie, _hidl_cb);
+        }
+        Return<void> loadPhraseSoundModel_2_1(
+            const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+            const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+            loadPhraseSoundModel_2_1_cb _hidl_cb) override {
+            return mImpl->loadPhraseSoundModel_2_1(soundModel, callback, cookie, _hidl_cb);
+        }
+        Return<int32_t> startRecognition_2_1(int32_t modelHandle,
+                                             const V2_1::ISoundTriggerHw::RecognitionConfig& config,
+                                             const sp<V2_1::ISoundTriggerHwCallback>& /*callback*/,
+                                             int32_t /*cookie*/) override {
+            return mImpl->startRecognition_2_1(modelHandle, config);
+        }
+
+       private:
+        sp<SoundTriggerHw> mImpl;
+    };
+
+    class SoundModelClient_2_1 : public SoundModelClient {
+       public:
+        SoundModelClient_2_1(uint32_t id, V2_1::ISoundTriggerHwCallback::CallbackCookie cookie,
+                             sp<V2_1::ISoundTriggerHwCallback> callback)
+            : SoundModelClient(id, cookie), mCallback(callback) {}
+
+        void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+        void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
+
+       private:
+        sp<V2_1::ISoundTriggerHwCallback> mCallback;
+    };
+};
+
+extern "C" ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* name);
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace soundtrigger
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SOUNDTRIGGER_V2_1_SOUNDTRIGGERHW_H
diff --git a/soundtrigger/2.1/vts/functional/Android.bp b/soundtrigger/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..925a17c
--- /dev/null
+++ b/soundtrigger/2.1/vts/functional/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalSoundtriggerV2_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalSoundtriggerV2_1TargetTest.cpp"],
+    static_libs: [
+                 "android.hidl.allocator@1.0",
+                 "android.hidl.memory@1.0",
+                 "android.hardware.soundtrigger@2.0",
+                 "android.hardware.soundtrigger@2.1",
+                 "libhidlmemory"
+                 ],
+}
diff --git a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
new file mode 100644
index 0000000..fdd5f0d
--- /dev/null
+++ b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SoundTriggerHidlHalTest"
+#include <stdlib.h>
+#include <time.h>
+
+#include <condition_variable>
+#include <mutex>
+
+#include <android/log.h>
+#include <cutils/native_handle.h>
+#include <log/log.h>
+
+#include <android/hardware/audio/common/2.0/types.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.0/types.h>
+#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <hidlmemory/mapping.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#define SHORT_TIMEOUT_PERIOD (1)
+
+using ::android::sp;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra;
+using ::android::hardware::soundtrigger::V2_0::RecognitionMode;
+using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
+using ::android::hardware::soundtrigger::V2_0::SoundModelType;
+using V2_0_ISoundTriggerHw = ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
+using V2_0_ISoundTriggerHwCallback =
+    ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
+using ::android::hardware::soundtrigger::V2_1::ISoundTriggerHw;
+using ::android::hardware::soundtrigger::V2_1::ISoundTriggerHwCallback;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+/**
+ * Test code uses this class to wait for notification from callback.
+ */
+class Monitor {
+   public:
+    Monitor() : mCount(0) {}
+
+    /**
+     * Adds 1 to the internal counter and unblocks one of the waiting threads.
+     */
+    void notify() {
+        std::unique_lock<std::mutex> lock(mMtx);
+        mCount++;
+        mCv.notify_one();
+    }
+
+    /**
+     * Blocks until the internal counter becomes greater than 0.
+     *
+     * If notified, this method decreases the counter by 1 and returns true.
+     * If timeout, returns false.
+     */
+    bool wait(int timeoutSeconds) {
+        auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(timeoutSeconds);
+        std::unique_lock<std::mutex> lock(mMtx);
+        if (!mCv.wait_until(lock, deadline, [& count = mCount] { return count > 0; })) {
+            return false;
+        }
+        mCount--;
+        return true;
+    }
+
+   private:
+    std::mutex mMtx;
+    std::condition_variable mCv;
+    int mCount;
+};
+
+// The main test class for Sound Trigger HIDL HAL.
+class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>();
+        ASSERT_NE(nullptr, mSoundTriggerHal.get());
+        mCallback = new SoundTriggerHwCallback(*this);
+        ASSERT_NE(nullptr, mCallback.get());
+    }
+
+    static void SetUpTestCase() { srand(1234); }
+
+    class SoundTriggerHwCallback : public ISoundTriggerHwCallback {
+       private:
+        SoundTriggerHidlTest& mParent;
+
+       public:
+        SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {}
+
+        Return<void> recognitionCallback(const V2_0_ISoundTriggerHwCallback::RecognitionEvent& event
+                                             __unused,
+                                         int32_t cookie __unused) override {
+            ALOGI("%s", __FUNCTION__);
+            return Void();
+        };
+
+        Return<void> phraseRecognitionCallback(
+            const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
+            int32_t cookie __unused) override {
+            ALOGI("%s", __FUNCTION__);
+            return Void();
+        };
+
+        Return<void> soundModelCallback(const V2_0_ISoundTriggerHwCallback::ModelEvent& event,
+                                        int32_t cookie __unused) override {
+            ALOGI("%s", __FUNCTION__);
+            mParent.lastModelEvent_2_0 = event;
+            mParent.monitor.notify();
+            return Void();
+        }
+
+        Return<void> recognitionCallback_2_1(const ISoundTriggerHwCallback::RecognitionEvent& event
+                                                 __unused,
+                                             int32_t cookie __unused) override {
+            ALOGI("%s", __FUNCTION__);
+            return Void();
+        }
+
+        Return<void> phraseRecognitionCallback_2_1(
+            const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
+            int32_t cookie __unused) override {
+            ALOGI("%s", __FUNCTION__);
+            return Void();
+        }
+
+        Return<void> soundModelCallback_2_1(const ISoundTriggerHwCallback::ModelEvent& event,
+                                            int32_t cookie __unused) {
+            ALOGI("%s", __FUNCTION__);
+            mParent.lastModelEvent = event;
+            mParent.monitor.notify();
+            return Void();
+        }
+    };
+
+    virtual void TearDown() override {}
+
+    Monitor monitor;
+    // updated by soundModelCallback()
+    V2_0_ISoundTriggerHwCallback::ModelEvent lastModelEvent_2_0;
+    // updated by soundModelCallback_2_1()
+    ISoundTriggerHwCallback::ModelEvent lastModelEvent;
+
+   protected:
+    sp<ISoundTriggerHw> mSoundTriggerHal;
+    sp<SoundTriggerHwCallback> mCallback;
+};
+
+/**
+ * Test ISoundTriggerHw::getProperties() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the method returns 0 (no error)
+ *  - the implementation supports at least one sound model and one key phrase
+ *  - the implementation supports at least VOICE_TRIGGER recognition mode
+ */
+TEST_F(SoundTriggerHidlTest, GetProperties) {
+    ISoundTriggerHw::Properties halProperties;
+    Return<void> hidlReturn;
+    int ret = -ENODEV;
+
+    hidlReturn = mSoundTriggerHal->getProperties([&](int rc, auto res) {
+        ret = rc;
+        halProperties = res;
+    });
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_EQ(0, ret);
+    EXPECT_GT(halProperties.maxSoundModels, 0u);
+    EXPECT_GT(halProperties.maxKeyPhrases, 0u);
+    EXPECT_NE(0u, (halProperties.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER));
+}
+
+/**
+ * Test ISoundTriggerHw::loadPhraseSoundModel() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when passed a malformed sound model
+ *
+ * There is no way to verify that implementation actually can load a sound model because each
+ * sound model is vendor specific.
+ */
+TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) {
+    Return<void> hidlReturn;
+    int ret = -ENODEV;
+    V2_0_ISoundTriggerHw::PhraseSoundModel model;
+    SoundModelHandle handle;
+
+    model.common.type = SoundModelType::UNKNOWN;
+
+    hidlReturn =
+        mSoundTriggerHal->loadPhraseSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
+            ret = retval;
+            handle = res;
+        });
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadPhraseSoundModel_2_1() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when passed a malformed sound model
+ *
+ * There is no way to verify that implementation actually can load a sound model because each
+ * sound model is vendor specific.
+ */
+TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail_2_1) {
+    Return<void> hidlReturn;
+    int ret = -ENODEV;
+    ISoundTriggerHw::PhraseSoundModel model;
+    SoundModelHandle handle;
+
+    model.common.header.type = SoundModelType::UNKNOWN;
+
+    hidlReturn = mSoundTriggerHal->loadPhraseSoundModel_2_1(model, mCallback, 0,
+                                                            [&](int32_t retval, auto res) {
+                                                                ret = retval;
+                                                                handle = res;
+                                                            });
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel() method
+ *
+ * Verifies that:
+ *  - the implementation returns an error when passed an empty sound model
+ */
+TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail) {
+    int ret = -ENODEV;
+    V2_0_ISoundTriggerHw::SoundModel model;
+    SoundModelHandle handle = 0;
+
+    model.type = SoundModelType::GENERIC;
+
+    Return<void> loadReturn =
+        mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
+            ret = retval;
+            handle = res;
+        });
+
+    EXPECT_TRUE(loadReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel() method
+ *
+ * Verifies that:
+ *  - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
+    int ret = -ENODEV;
+    V2_0_ISoundTriggerHw::SoundModel model;
+    SoundModelHandle handle = 0;
+
+    model.type = SoundModelType::GENERIC;
+    model.data.resize(100);
+    for (auto& d : model.data) {
+        d = rand();
+    }
+
+    Return<void> loadReturn =
+        mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
+            ret = retval;
+            handle = res;
+        });
+
+    EXPECT_TRUE(loadReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel_2_1() method
+ *
+ * Verifies that:
+ *  - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail_2_1) {
+    int ret = -ENODEV;
+    ISoundTriggerHw::SoundModel model;
+    SoundModelHandle handle = 0;
+
+    model.header.type = SoundModelType::GENERIC;
+
+    Return<void> loadReturn =
+        mSoundTriggerHal->loadSoundModel_2_1(model, mCallback, 0, [&](int32_t retval, auto res) {
+            ret = retval;
+            handle = res;
+        });
+
+    EXPECT_TRUE(loadReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel_2_1() method
+ *
+ * Verifies that:
+ *  - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail_2_1) {
+    int ret = -ENODEV;
+    ISoundTriggerHw::SoundModel model;
+    SoundModelHandle handle = 0;
+
+    model.header.type = SoundModelType::GENERIC;
+    sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+    ASSERT_NE(nullptr, ashmem.get());
+    hidl_memory hmemory;
+    int size = 100;
+    Return<void> allocReturn = ashmem->allocate(size, [&](bool success, const hidl_memory& m) {
+        ASSERT_TRUE(success);
+        hmemory = m;
+    });
+    sp<IMemory> memory = ::android::hardware::mapMemory(hmemory);
+    ASSERT_NE(nullptr, memory.get());
+    memory->update();
+    for (uint8_t *p = static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())); size >= 0;
+         p++, size--) {
+        *p = rand();
+    }
+
+    Return<void> loadReturn =
+        mSoundTriggerHal->loadSoundModel_2_1(model, mCallback, 0, [&](int32_t retval, auto res) {
+            ret = retval;
+            handle = res;
+        });
+
+    EXPECT_TRUE(loadReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::unloadSoundModel() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when called without a valid loaded sound model
+ *
+ */
+TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) {
+    Return<int32_t> hidlReturn(0);
+    SoundModelHandle halHandle = 0;
+
+    hidlReturn = mSoundTriggerHal->unloadSoundModel(halHandle);
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::startRecognition() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when called without a valid loaded sound model
+ *
+ * There is no way to verify that implementation actually starts recognition because no model can
+ * be loaded.
+ */
+TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
+    Return<int32_t> hidlReturn(0);
+    SoundModelHandle handle = 0;
+    PhraseRecognitionExtra phrase;
+    V2_0_ISoundTriggerHw::RecognitionConfig config;
+
+    config.captureHandle = 0;
+    config.captureDevice = AudioDevice::IN_BUILTIN_MIC;
+    phrase.id = 0;
+    phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
+    phrase.confidenceLevel = 0;
+
+    config.phrases.setToExternal(&phrase, 1);
+
+    hidlReturn = mSoundTriggerHal->startRecognition(handle, config, mCallback, 0);
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::startRecognition_2_1() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when called without a valid loaded sound model
+ *
+ * There is no way to verify that implementation actually starts recognition because no model can
+ * be loaded.
+ */
+TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail_2_1) {
+    Return<int32_t> hidlReturn(0);
+    SoundModelHandle handle = 0;
+    PhraseRecognitionExtra phrase;
+    ISoundTriggerHw::RecognitionConfig config;
+
+    config.header.captureHandle = 0;
+    config.header.captureDevice = AudioDevice::IN_BUILTIN_MIC;
+    phrase.id = 0;
+    phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
+    phrase.confidenceLevel = 0;
+
+    config.header.phrases.setToExternal(&phrase, 1);
+
+    hidlReturn = mSoundTriggerHal->startRecognition_2_1(handle, config, mCallback, 0);
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::stopRecognition() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when called without an active recognition running
+ *
+ */
+TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
+    Return<int32_t> hidlReturn(0);
+    SoundModelHandle handle = 0;
+
+    hidlReturn = mSoundTriggerHal->stopRecognition(handle);
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::stopAllRecognitions() method
+ *
+ * Verifies that:
+ *  - the implementation implements this optional method or indicates it is not supported by
+ *  returning -ENOSYS
+ */
+TEST_F(SoundTriggerHidlTest, stopAllRecognitions) {
+    Return<int32_t> hidlReturn(0);
+
+    hidlReturn = mSoundTriggerHal->stopAllRecognitions();
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
+}
diff --git a/tests/extension/light/2.0/default/android.hardware.tests.extension.light@2.0-service.rc b/tests/extension/light/2.0/default/android.hardware.tests.extension.light@2.0-service.rc
index 8f379ee..0b8515a 100644
--- a/tests/extension/light/2.0/default/android.hardware.tests.extension.light@2.0-service.rc
+++ b/tests/extension/light/2.0/default/android.hardware.tests.extension.light@2.0-service.rc
@@ -1,4 +1,4 @@
-service light-ext-2-0 /vendor/bin/hw/android.hardware.tests.extension.light@2.0-service
+service vendor.light-ext-2-0 /vendor/bin/hw/android.hardware.tests.extension.light@2.0-service
     class hal
     user system
-    group system
\ No newline at end of file
+    group system
diff --git a/thermal/1.0/default/android.hardware.thermal@1.0-service.rc b/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
index cbc0f65..cf9bdee 100644
--- a/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
+++ b/thermal/1.0/default/android.hardware.thermal@1.0-service.rc
@@ -1,4 +1,4 @@
-service thermal-hal-1-0 /vendor/bin/hw/android.hardware.thermal@1.0-service
+service vendor.thermal-hal-1-0 /vendor/bin/hw/android.hardware.thermal@1.0-service
     class hal
     user system
     group system
diff --git a/tv/cec/1.0/default/HdmiCec.cpp b/tv/cec/1.0/default/HdmiCec.cpp
index ebe2681..171bdfe 100644
--- a/tv/cec/1.0/default/HdmiCec.cpp
+++ b/tv/cec/1.0/default/HdmiCec.cpp
@@ -264,8 +264,7 @@
 
 sp<IHdmiCecCallback> HdmiCec::mCallback = nullptr;
 
-HdmiCec::HdmiCec(hdmi_cec_device_t* device) : mDevice(device) {
-}
+HdmiCec::HdmiCec(hdmi_cec_device_t* device) : mDevice(device) {}
 
 // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
 Return<Result> HdmiCec::addLogicalAddress(CecLogicalAddress addr) {
@@ -319,8 +318,16 @@
 }
 
 Return<void> HdmiCec::setCallback(const sp<IHdmiCecCallback>& callback) {
-    mCallback = callback;
-    mDevice->register_event_callback(mDevice, eventCallback, nullptr);
+    if (mCallback != nullptr) {
+        mCallback->unlinkToDeath(this);
+        mCallback = nullptr;
+    }
+
+    if (callback != nullptr) {
+        mCallback = callback;
+        mCallback->linkToDeath(this, 0 /*cookie*/);
+        mDevice->register_event_callback(mDevice, eventCallback, nullptr);
+    }
     return Void();
 }
 
diff --git a/tv/cec/1.0/default/HdmiCec.h b/tv/cec/1.0/default/HdmiCec.h
index 34a3bb0..0133abc 100644
--- a/tv/cec/1.0/default/HdmiCec.h
+++ b/tv/cec/1.0/default/HdmiCec.h
@@ -47,7 +47,7 @@
 using ::android::hardware::hidl_string;
 using ::android::sp;
 
-struct HdmiCec : public IHdmiCec {
+struct HdmiCec : public IHdmiCec, public hidl_death_recipient {
     HdmiCec(hdmi_cec_device_t* device);
     // Methods from ::android::hardware::tv::cec::V1_0::IHdmiCec follow.
     Return<Result> addLogicalAddress(CecLogicalAddress addr)  override;
@@ -87,7 +87,12 @@
         }
     }
 
-private:
+    virtual void serviceDied(uint64_t /*cookie*/,
+                             const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+        setCallback(nullptr);
+    }
+
+   private:
     static sp<IHdmiCecCallback> mCallback;
     const hdmi_cec_device_t* mDevice;
 };
diff --git a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
index 9c80094..8595099 100644
--- a/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
+++ b/tv/cec/1.0/default/android.hardware.tv.cec@1.0-service.rc
@@ -1,4 +1,4 @@
-service cec-hal-1-0 /vendor/bin/hw/android.hardware.tv.cec@1.0-service
+service vendor.cec-hal-1-0 /vendor/bin/hw/android.hardware.tv.cec@1.0-service
     class hal
     user system
     group system
diff --git a/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc b/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
index dc6907c..972c654 100644
--- a/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
+++ b/tv/input/1.0/default/android.hardware.tv.input@1.0-service.rc
@@ -1,4 +1,4 @@
-service tv-input-1-0 /vendor/bin/hw/android.hardware.tv.input@1.0-service
+service vendor.tv-input-1-0 /vendor/bin/hw/android.hardware.tv.input@1.0-service
     class hal
     user system
     group system
diff --git a/update-base-files.sh b/update-base-files.sh
index bb99d22..75d2be5 100755
--- a/update-base-files.sh
+++ b/update-base-files.sh
@@ -31,8 +31,11 @@
 
 # system/core
 hidl-gen $options \
-         -o $ANDROID_BUILD_TOP/system/core/include/system/graphics-base.h \
+         -o $ANDROID_BUILD_TOP/system/core/include/system/graphics-base-v1.0.h \
          android.hardware.graphics.common@1.0
+hidl-gen $options \
+         -o $ANDROID_BUILD_TOP/system/core/include/system/graphics-base-v1.1.h \
+         android.hardware.graphics.common@1.1
 
 # system/media
 hidl-gen $options \
diff --git a/usb/1.0/default/android.hardware.usb@1.0-service.rc b/usb/1.0/default/android.hardware.usb@1.0-service.rc
index 6ea0720..b7a0c63 100644
--- a/usb/1.0/default/android.hardware.usb@1.0-service.rc
+++ b/usb/1.0/default/android.hardware.usb@1.0-service.rc
@@ -1,4 +1,4 @@
-service usb-hal-1-0 /vendor/bin/hw/android.hardware.usb@1.0-service
+service vendor.usb-hal-1-0 /vendor/bin/hw/android.hardware.usb@1.0-service
     class hal
     user system
     group system
diff --git a/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc b/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
index f027065..1123eab 100644
--- a/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
+++ b/vibrator/1.0/default/android.hardware.vibrator@1.0-service.rc
@@ -1,4 +1,4 @@
-service vibrator-1-0 /vendor/bin/hw/android.hardware.vibrator@1.0-service
+service vendor.vibrator-1-0 /vendor/bin/hw/android.hardware.vibrator@1.0-service
     class hal
     user system
     group system
diff --git a/vibrator/1.2/Android.bp b/vibrator/1.2/Android.bp
new file mode 100644
index 0000000..88192c1
--- /dev/null
+++ b/vibrator/1.2/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.vibrator@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IVibrator.hal",
+    ],
+    interfaces: [
+        "android.hardware.vibrator@1.0",
+        "android.hardware.vibrator@1.1",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "Effect",
+    ],
+    gen_java: true,
+}
+
diff --git a/vibrator/1.2/IVibrator.hal b/vibrator/1.2/IVibrator.hal
new file mode 100644
index 0000000..7244da1
--- /dev/null
+++ b/vibrator/1.2/IVibrator.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator@1.2;
+
+import @1.0::EffectStrength;
+import @1.0::Status;
+import @1.1::IVibrator;
+
+interface IVibrator extends @1.1::IVibrator {
+  /**
+   * Fire off a predefined haptic event.
+   *
+   * @param event The type of haptic event to trigger.
+   * @return status Whether the effect was successfully performed or not. Must
+   *     return Status::UNSUPPORTED_OPERATION is the effect is not supported.
+   * @return lengthMs The length of time the event is expected to take in
+   *     milliseconds. This doesn't need to be perfectly accurate, but should be a reasonable
+   *     approximation. Should be a positive, non-zero value if the returned status is Status::OK,
+   *     and set to 0 otherwise.
+   */
+  perform_1_2(Effect effect, EffectStrength strength)
+          generates (Status status, uint32_t lengthMs);
+};
diff --git a/vibrator/1.2/types.hal b/vibrator/1.2/types.hal
new file mode 100644
index 0000000..7604f2c
--- /dev/null
+++ b/vibrator/1.2/types.hal
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.vibrator@1.2;
+
+import @1.1::Effect_1_1;
+
+// Note that while the previous type had a version suffix, this type does not. This is because the
+// versions are already present in the namespace and thus don't need to also be embedded in the
+// name of the type.
+enum Effect : @1.1::Effect_1_1 {
+     /**
+      * A thud effect.
+      *
+      * This effect should solid feeling bump, like the depression of a heavy mechanical button.
+      */
+     THUD,
+     /**
+      * A pop effect.
+      *
+      * A short, quick burst effect.
+      */
+     POP,
+
+     /**
+      * A heavy click effect.
+      *
+      * This should produce a sharp striking sensation, like a click but stronger.
+      */
+     HEAVY_CLICK,
+
+     /**
+      * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a
+      * pattern that can be played as a ringtone with any audio, depending on the device.
+      */
+     RINGTONE_1,
+     RINGTONE_2,
+     RINGTONE_3,
+     RINGTONE_4,
+     RINGTONE_5,
+     RINGTONE_6,
+     RINGTONE_7,
+     RINGTONE_8,
+     RINGTONE_9,
+     RINGTONE_10,
+     RINGTONE_11,
+     RINGTONE_12,
+     RINGTONE_13,
+     RINGTONE_14,
+     RINGTONE_15,
+};
diff --git a/vibrator/1.2/vts/functional/Android.bp b/vibrator/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..3a4e2ef
--- /dev/null
+++ b/vibrator/1.2/vts/functional/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalVibratorV1_2TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalVibratorV1_2TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.vibrator@1.0",
+        "android.hardware.vibrator@1.1",
+        "android.hardware.vibrator@1.2",
+    ],
+}
+
diff --git a/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp b/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
new file mode 100644
index 0000000..d07d1b7
--- /dev/null
+++ b/vibrator/1.2/vts/functional/VtsHalVibratorV1_2TargetTest.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "vibrator_hidl_hal_test"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/vibrator/1.0/types.h>
+#include <android/hardware/vibrator/1.2/IVibrator.h>
+#include <android/hardware/vibrator/1.2/types.h>
+#include <unistd.h>
+
+using ::android::hardware::vibrator::V1_0::Status;
+using ::android::hardware::vibrator::V1_0::EffectStrength;
+using ::android::hardware::vibrator::V1_2::Effect;
+using ::android::hardware::vibrator::V1_2::IVibrator;
+using ::android::hardware::hidl_enum_iterator;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+// The main test class for VIBRATOR HIDL HAL 1.2.
+class VibratorHidlTest_1_2 : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        vibrator = ::testing::VtsHalHidlTargetTestBase::getService<IVibrator>();
+        ASSERT_NE(vibrator, nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+    sp<IVibrator> vibrator;
+};
+
+static void validatePerformEffect(Status status, uint32_t lengthMs) {
+    ASSERT_TRUE(status == Status::OK || status == Status::UNSUPPORTED_OPERATION);
+    if (status == Status::OK) {
+        ASSERT_GT(lengthMs, static_cast<uint32_t>(0))
+            << "Effects that return OK must return a non-zero duration";
+    } else {
+        ASSERT_EQ(lengthMs, static_cast<uint32_t>(0))
+            << "Effects that return UNSUPPORTED_OPERATION must have a duration of zero";
+    }
+}
+
+TEST_F(VibratorHidlTest_1_2, PerformEffect_1_2) {
+    for (const auto& effect : hidl_enum_iterator<Effect>()) {
+        for (const auto& strength : hidl_enum_iterator<EffectStrength>()) {
+            vibrator->perform_1_2(effect, strength, validatePerformEffect);
+        }
+    }
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/vr/1.0/default/android.hardware.vr@1.0-service.rc b/vr/1.0/default/android.hardware.vr@1.0-service.rc
index bcc6416..fc4934c 100644
--- a/vr/1.0/default/android.hardware.vr@1.0-service.rc
+++ b/vr/1.0/default/android.hardware.vr@1.0-service.rc
@@ -1,4 +1,4 @@
-service vr-1-0 /vendor/bin/hw/android.hardware.vr@1.0-service
+service vendor.vr-1-0 /vendor/bin/hw/android.hardware.vr@1.0-service
     class hal
     user system
     group system
diff --git a/wifi/1.0/types.hal b/wifi/1.0/types.hal
index b9fb0bd..4b8d68a 100644
--- a/wifi/1.0/types.hal
+++ b/wifi/1.0/types.hal
@@ -1411,7 +1411,8 @@
   vec<uint8_t> extendedServiceSpecificInfo;
   /**
    * The match filter from the discovery packet (publish or subscribe) which caused service
-   * discovery. Matches the peer's |NanDiscoveryCommonConfig.txMatchFilter|.
+   * discovery. Matches the |NanDiscoveryCommonConfig.txMatchFilter| of the peer's Unsolicited
+   * publish message or of the local device's Active subscribe message.
    * Max length: |NanCapabilities.maxMatchFilterLen|.
    * NAN Spec: Service Descriptor Attribute (SDA) / Matching Filter
    */
diff --git a/wifi/1.1/default/Android.mk b/wifi/1.1/default/Android.mk
deleted file mode 100644
index ee912c5..0000000
--- a/wifi/1.1/default/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.wifi@1.0-service
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_CPPFLAGS := -Wall -Werror -Wextra
-ifdef WIFI_HIDL_FEATURE_AWARE
-LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE
-endif
-LOCAL_SRC_FILES := \
-    hidl_struct_util.cpp \
-    hidl_sync_util.cpp \
-    service.cpp \
-    wifi.cpp \
-    wifi_ap_iface.cpp \
-    wifi_chip.cpp \
-    wifi_legacy_hal.cpp \
-    wifi_legacy_hal_stubs.cpp \
-    wifi_mode_controller.cpp \
-    wifi_nan_iface.cpp \
-    wifi_p2p_iface.cpp \
-    wifi_rtt_controller.cpp \
-    wifi_sta_iface.cpp \
-    wifi_status_util.cpp
-LOCAL_SHARED_LIBRARIES := \
-    libbase \
-    libcutils \
-    libhidlbase \
-    libhidltransport \
-    liblog \
-    libnl \
-    libutils \
-    libwifi-hal \
-    libwifi-system-iface \
-    android.hardware.wifi@1.0 \
-    android.hardware.wifi@1.1
-LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
-include $(BUILD_EXECUTABLE)
diff --git a/wifi/1.1/default/android.hardware.wifi@1.0-service.rc b/wifi/1.1/default/android.hardware.wifi@1.0-service.rc
deleted file mode 100644
index 696b1f9..0000000
--- a/wifi/1.1/default/android.hardware.wifi@1.0-service.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
-    class hal
-    user wifi
-    group wifi gps
diff --git a/wifi/1.1/default/hidl_callback_util.h b/wifi/1.1/default/hidl_callback_util.h
deleted file mode 100644
index fb13622..0000000
--- a/wifi/1.1/default/hidl_callback_util.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef HIDL_CALLBACK_UTIL_H_
-#define HIDL_CALLBACK_UTIL_H_
-
-#include <set>
-
-#include <hidl/HidlSupport.h>
-
-namespace {
-// Type of callback invoked by the death handler.
-using on_death_cb_function = std::function<void(uint64_t)>;
-
-// Private class used to keep track of death of individual
-// callbacks stored in HidlCallbackHandler.
-template <typename CallbackType>
-class HidlDeathHandler : public android::hardware::hidl_death_recipient {
- public:
-  HidlDeathHandler(const on_death_cb_function& user_cb_function)
-      : cb_function_(user_cb_function) {}
-  ~HidlDeathHandler() = default;
-
-  // Death notification for callbacks.
-  void serviceDied(
-      uint64_t cookie,
-      const android::wp<android::hidl::base::V1_0::IBase>& /* who */) override {
-    cb_function_(cookie);
-  }
-
- private:
-  on_death_cb_function cb_function_;
-
-  DISALLOW_COPY_AND_ASSIGN(HidlDeathHandler);
-};
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace hidl_callback_util {
-template <typename CallbackType>
-// Provides a class to manage callbacks for the various HIDL interfaces and
-// handle the death of the process hosting each callback.
-class HidlCallbackHandler {
- public:
-  HidlCallbackHandler()
-      : death_handler_(new HidlDeathHandler<CallbackType>(
-            std::bind(&HidlCallbackHandler::onObjectDeath,
-                      this,
-                      std::placeholders::_1))) {}
-  ~HidlCallbackHandler() = default;
-
-  bool addCallback(const sp<CallbackType>& cb) {
-    // TODO(b/33818800): Can't compare proxies yet. So, use the cookie
-    // (callback proxy's raw pointer) to track the death of individual clients.
-    uint64_t cookie = reinterpret_cast<uint64_t>(cb.get());
-    if (cb_set_.find(cb) != cb_set_.end()) {
-      LOG(WARNING) << "Duplicate death notification registration";
-      return true;
-    }
-    if (!cb->linkToDeath(death_handler_, cookie)) {
-      LOG(ERROR) << "Failed to register death notification";
-      return false;
-    }
-    cb_set_.insert(cb);
-    return true;
-  }
-
-  const std::set<android::sp<CallbackType>>& getCallbacks() { return cb_set_; }
-
-  // Death notification for callbacks.
-  void onObjectDeath(uint64_t cookie) {
-    CallbackType* cb = reinterpret_cast<CallbackType*>(cookie);
-    const auto& iter = cb_set_.find(cb);
-    if (iter == cb_set_.end()) {
-      LOG(ERROR) << "Unknown callback death notification received";
-      return;
-    }
-    cb_set_.erase(iter);
-    LOG(DEBUG) << "Dead callback removed from list";
-  }
-
-  void invalidate() {
-    for (const sp<CallbackType>& cb : cb_set_) {
-      if (!cb->unlinkToDeath(death_handler_)) {
-        LOG(ERROR) << "Failed to deregister death notification";
-      }
-    }
-    cb_set_.clear();
-  }
-
- private:
-  std::set<sp<CallbackType>> cb_set_;
-  sp<HidlDeathHandler<CallbackType>> death_handler_;
-
-  DISALLOW_COPY_AND_ASSIGN(HidlCallbackHandler);
-};
-
-}  // namespace hidl_callback_util
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_CALLBACK_UTIL_H_
diff --git a/wifi/1.1/default/hidl_return_util.h b/wifi/1.1/default/hidl_return_util.h
deleted file mode 100644
index f36c8bd..0000000
--- a/wifi/1.1/default/hidl_return_util.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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 HIDL_RETURN_UTIL_H_
-#define HIDL_RETURN_UTIL_H_
-
-#include "hidl_sync_util.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace hidl_return_util {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * These utility functions are used to invoke a method on the provided
- * HIDL interface object.
- * These functions checks if the provided HIDL interface object is valid.
- * a) if valid, Invokes the corresponding internal implementation function of
- * the HIDL method. It then invokes the HIDL continuation callback with
- * the status and any returned values.
- * b) if invalid, invokes the HIDL continuation callback with the
- * provided error status and default values.
- */
-// Use for HIDL methods which return only an instance of WifiStatus.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj,
-    WifiStatusCode status_code_if_invalid,
-    WorkFuncT&& work,
-    const std::function<void(const WifiStatus&)>& hidl_cb,
-    Args&&... args) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (obj->isValid()) {
-    hidl_cb((obj->*work)(std::forward<Args>(args)...));
-  } else {
-    hidl_cb(createWifiStatus(status_code_if_invalid));
-  }
-  return Void();
-}
-
-// Use for HIDL methods which return only an instance of WifiStatus.
-// This version passes the global lock acquired to the body of the method.
-// Note: Only used by IWifi::stop() currently.
-template <typename ObjT, typename WorkFuncT, typename... Args>
-Return<void> validateAndCallWithLock(
-    ObjT* obj,
-    WifiStatusCode status_code_if_invalid,
-    WorkFuncT&& work,
-    const std::function<void(const WifiStatus&)>& hidl_cb,
-    Args&&... args) {
-  auto lock = hidl_sync_util::acquireGlobalLock();
-  if (obj->isValid()) {
-    hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...));
-  } else {
-    hidl_cb(createWifiStatus(status_code_if_invalid));
-  }
-  return Void();
-}
-
-// Use for HIDL methods which return instance of WifiStatus and a single return
-// value.
-template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj,
-    WifiStatusCode status_code_if_invalid,
-    WorkFuncT&& work,
-    const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
-    Args&&... args) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (obj->isValid()) {
-    const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
-    const WifiStatus& status = std::get<0>(ret_pair);
-    const auto& ret_value = std::get<1>(ret_pair);
-    hidl_cb(status, ret_value);
-  } else {
-    hidl_cb(createWifiStatus(status_code_if_invalid),
-            typename std::remove_reference<ReturnT>::type());
-  }
-  return Void();
-}
-
-// Use for HIDL methods which return instance of WifiStatus and 2 return
-// values.
-template <typename ObjT,
-          typename WorkFuncT,
-          typename ReturnT1,
-          typename ReturnT2,
-          typename... Args>
-Return<void> validateAndCall(
-    ObjT* obj,
-    WifiStatusCode status_code_if_invalid,
-    WorkFuncT&& work,
-    const std::function<void(const WifiStatus&, ReturnT1, ReturnT2)>& hidl_cb,
-    Args&&... args) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (obj->isValid()) {
-    const auto& ret_tuple = (obj->*work)(std::forward<Args>(args)...);
-    const WifiStatus& status = std::get<0>(ret_tuple);
-    const auto& ret_value1 = std::get<1>(ret_tuple);
-    const auto& ret_value2 = std::get<2>(ret_tuple);
-    hidl_cb(status, ret_value1, ret_value2);
-  } else {
-    hidl_cb(createWifiStatus(status_code_if_invalid),
-            typename std::remove_reference<ReturnT1>::type(),
-            typename std::remove_reference<ReturnT2>::type());
-  }
-  return Void();
-}
-
-}  // namespace hidl_util
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_RETURN_UTIL_H_
diff --git a/wifi/1.1/default/hidl_struct_util.cpp b/wifi/1.1/default/hidl_struct_util.cpp
deleted file mode 100644
index c53cdc5..0000000
--- a/wifi/1.1/default/hidl_struct_util.cpp
+++ /dev/null
@@ -1,2215 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-#include <utils/SystemClock.h>
-
-#include "hidl_struct_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace hidl_struct_util {
-
-hidl_string safeConvertChar(const char* str, size_t max_len) {
-  const char* c = str;
-  size_t size = 0;
-  while (*c && (unsigned char)*c < 128 && size < max_len) {
-    ++size;
-    ++c;
-  }
-  return hidl_string(str, size);
-}
-
-IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(
-    uint32_t feature) {
-  using HidlChipCaps = IWifiChip::ChipCapabilityMask;
-  switch (feature) {
-    case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
-      return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP;
-    case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
-      return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP;
-    case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
-      return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT;
-    case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
-      return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT;
-    case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
-      return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
-  };
-  CHECK(false) << "Unknown legacy feature: " << feature;
-  return {};
-}
-
-IWifiStaIface::StaIfaceCapabilityMask
-convertLegacyLoggerFeatureToHidlStaIfaceCapability(uint32_t feature) {
-  using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-  switch (feature) {
-    case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
-      return HidlStaIfaceCaps::DEBUG_PACKET_FATE;
-  };
-  CHECK(false) << "Unknown legacy feature: " << feature;
-  return {};
-}
-
-V1_1::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
-    uint32_t feature) {
-  using HidlChipCaps = V1_1::IWifiChip::ChipCapabilityMask;
-  switch (feature) {
-    case WIFI_FEATURE_SET_TX_POWER_LIMIT:
-      return HidlChipCaps::SET_TX_POWER_LIMIT;
-    case WIFI_FEATURE_D2D_RTT:
-      return HidlChipCaps::D2D_RTT;
-    case WIFI_FEATURE_D2AP_RTT:
-      return HidlChipCaps::D2AP_RTT;
-  };
-  CHECK(false) << "Unknown legacy feature: " << feature;
-  return {};
-}
-
-IWifiStaIface::StaIfaceCapabilityMask
-convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) {
-  using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-  switch (feature) {
-    case WIFI_FEATURE_GSCAN:
-      return HidlStaIfaceCaps::BACKGROUND_SCAN;
-    case WIFI_FEATURE_LINK_LAYER_STATS:
-      return HidlStaIfaceCaps::LINK_LAYER_STATS;
-    case WIFI_FEATURE_RSSI_MONITOR:
-      return HidlStaIfaceCaps::RSSI_MONITOR;
-    case WIFI_FEATURE_CONTROL_ROAMING:
-      return HidlStaIfaceCaps::CONTROL_ROAMING;
-    case WIFI_FEATURE_IE_WHITELIST:
-      return HidlStaIfaceCaps::PROBE_IE_WHITELIST;
-    case WIFI_FEATURE_SCAN_RAND:
-      return HidlStaIfaceCaps::SCAN_RAND;
-    case WIFI_FEATURE_INFRA_5G:
-      return HidlStaIfaceCaps::STA_5G;
-    case WIFI_FEATURE_HOTSPOT:
-      return HidlStaIfaceCaps::HOTSPOT;
-    case WIFI_FEATURE_PNO:
-      return HidlStaIfaceCaps::PNO;
-    case WIFI_FEATURE_TDLS:
-      return HidlStaIfaceCaps::TDLS;
-    case WIFI_FEATURE_TDLS_OFFCHANNEL:
-      return HidlStaIfaceCaps::TDLS_OFFCHANNEL;
-    case WIFI_FEATURE_CONFIG_NDO:
-      return HidlStaIfaceCaps::ND_OFFLOAD;
-    case WIFI_FEATURE_MKEEP_ALIVE:
-      return HidlStaIfaceCaps::KEEP_ALIVE;
-  };
-  CHECK(false) << "Unknown legacy feature: " << feature;
-  return {};
-}
-
-bool convertLegacyFeaturesToHidlChipCapabilities(
-    uint32_t legacy_feature_set,
-    uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps) {
-  if (!hidl_caps) {
-    return false;
-  }
-  *hidl_caps = {};
-  using HidlChipCaps = IWifiChip::ChipCapabilityMask;
-  for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
-                             legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
-                             legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
-                             legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
-                             legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
-    if (feature & legacy_logger_feature_set) {
-      *hidl_caps |= convertLegacyLoggerFeatureToHidlChipCapability(feature);
-    }
-  }
-  for (const auto feature : {WIFI_FEATURE_SET_TX_POWER_LIMIT,
-                             WIFI_FEATURE_D2D_RTT,
-                             WIFI_FEATURE_D2AP_RTT}) {
-    if (feature & legacy_feature_set) {
-      *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
-    }
-  }
-  // There are no flags for these 3 in the legacy feature set. Adding them to
-  // the set because all the current devices support it.
-  *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
-  *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
-  *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
-  return true;
-}
-
-WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(
-    uint32_t flag) {
-  switch (flag) {
-    case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
-      return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
-    case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
-      return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
-  };
-  CHECK(false) << "Unknown legacy flag: " << flag;
-  return {};
-}
-
-bool convertLegacyDebugRingBufferStatusToHidl(
-    const legacy_hal::wifi_ring_buffer_status& legacy_status,
-    WifiDebugRingBufferStatus* hidl_status) {
-  if (!hidl_status) {
-    return false;
-  }
-  *hidl_status = {};
-  hidl_status->ringName = safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
-        sizeof(legacy_status.name));
-  hidl_status->flags = 0;
-  for (const auto flag : {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES,
-                          WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
-    if (flag & legacy_status.flags) {
-      hidl_status->flags |=
-          static_cast<std::underlying_type<WifiDebugRingBufferFlags>::type>(
-              convertLegacyDebugRingBufferFlagsToHidl(flag));
-    }
-  }
-  hidl_status->ringId = legacy_status.ring_id;
-  hidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
-  // Calculate free size of the ring the buffer. We don't need to send the
-  // exact read/write pointers that were there in the legacy HAL interface.
-  if (legacy_status.written_bytes >= legacy_status.read_bytes) {
-    hidl_status->freeSizeInBytes =
-        legacy_status.ring_buffer_byte_size -
-        (legacy_status.written_bytes - legacy_status.read_bytes);
-  } else {
-    hidl_status->freeSizeInBytes =
-        legacy_status.read_bytes - legacy_status.written_bytes;
-  }
-  hidl_status->verboseLevel = legacy_status.verbose_level;
-  return true;
-}
-
-bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
-    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
-    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
-  if (!hidl_status_vec) {
-    return false;
-  }
-  *hidl_status_vec = {};
-  for (const auto& legacy_status : legacy_status_vec) {
-    WifiDebugRingBufferStatus hidl_status;
-    if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status,
-                                                  &hidl_status)) {
-      return false;
-    }
-    hidl_status_vec->push_back(hidl_status);
-  }
-  return true;
-}
-
-bool convertLegacyWakeReasonStatsToHidl(
-    const legacy_hal::WakeReasonStats& legacy_stats,
-    WifiDebugHostWakeReasonStats* hidl_stats) {
-  if (!hidl_stats) {
-    return false;
-  }
-  *hidl_stats = {};
-  hidl_stats->totalCmdEventWakeCnt =
-      legacy_stats.wake_reason_cnt.total_cmd_event_wake;
-  hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
-  hidl_stats->totalDriverFwLocalWakeCnt =
-      legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
-  hidl_stats->driverFwLocalWakeCntPerType =
-      legacy_stats.driver_fw_local_wake_cnt;
-  hidl_stats->totalRxPacketWakeCnt =
-      legacy_stats.wake_reason_cnt.total_rx_data_wake;
-  hidl_stats->rxPktWakeDetails.rxUnicastCnt =
-      legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
-  hidl_stats->rxPktWakeDetails.rxMulticastCnt =
-      legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
-  hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
-      legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
-  hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
-      legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
-          .ipv4_rx_multicast_addr_cnt;
-  hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
-      legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
-          .ipv6_rx_multicast_addr_cnt;
-  hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
-      legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
-          .other_rx_multicast_addr_cnt;
-  hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
-      legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
-  hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
-      legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
-  hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
-      legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
-  hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
-      legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
-  hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
-      legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
-  return true;
-}
-
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
-    V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
-  switch (hidl_scenario) {
-    case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
-      return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
-  };
-  CHECK(false);
-}
-
-bool convertLegacyFeaturesToHidlStaCapabilities(
-    uint32_t legacy_feature_set,
-    uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps) {
-  if (!hidl_caps) {
-    return false;
-  }
-  *hidl_caps = {};
-  using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
-  for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
-    if (feature & legacy_logger_feature_set) {
-      *hidl_caps |= convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
-    }
-  }
-  for (const auto feature : {WIFI_FEATURE_GSCAN,
-                             WIFI_FEATURE_LINK_LAYER_STATS,
-                             WIFI_FEATURE_RSSI_MONITOR,
-                             WIFI_FEATURE_CONTROL_ROAMING,
-                             WIFI_FEATURE_IE_WHITELIST,
-                             WIFI_FEATURE_SCAN_RAND,
-                             WIFI_FEATURE_INFRA_5G,
-                             WIFI_FEATURE_HOTSPOT,
-                             WIFI_FEATURE_PNO,
-                             WIFI_FEATURE_TDLS,
-                             WIFI_FEATURE_TDLS_OFFCHANNEL,
-                             WIFI_FEATURE_CONFIG_NDO,
-                             WIFI_FEATURE_MKEEP_ALIVE}) {
-    if (feature & legacy_feature_set) {
-      *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
-    }
-  }
-  // There is no flag for this one in the legacy feature set. Adding it to the
-  // set because all the current devices support it.
-  *hidl_caps |= HidlStaIfaceCaps::APF;
-  return true;
-}
-
-bool convertLegacyApfCapabilitiesToHidl(
-    const legacy_hal::PacketFilterCapabilities& legacy_caps,
-    StaApfPacketFilterCapabilities* hidl_caps) {
-  if (!hidl_caps) {
-    return false;
-  }
-  *hidl_caps = {};
-  hidl_caps->version = legacy_caps.version;
-  hidl_caps->maxLength = legacy_caps.max_len;
-  return true;
-}
-
-uint8_t convertHidlGscanReportEventFlagToLegacy(
-    StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
-  using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
-  switch (hidl_flag) {
-    case HidlFlag::EACH_SCAN:
-      return REPORT_EVENTS_EACH_SCAN;
-    case HidlFlag::FULL_RESULTS:
-      return REPORT_EVENTS_FULL_RESULTS;
-    case HidlFlag::NO_BATCH:
-      return REPORT_EVENTS_NO_BATCH;
-  };
-  CHECK(false);
-}
-
-StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(uint8_t legacy_flag) {
-  switch (legacy_flag) {
-    case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
-      return StaScanDataFlagMask::INTERRUPTED;
-  };
-  CHECK(false) << "Unknown legacy flag: " << legacy_flag;
-  // To silence the compiler warning about reaching the end of non-void
-  // function.
-  return {};
-}
-
-bool convertLegacyGscanCapabilitiesToHidl(
-    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
-    StaBackgroundScanCapabilities* hidl_caps) {
-  if (!hidl_caps) {
-    return false;
-  }
-  *hidl_caps = {};
-  hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
-  hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
-  hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
-  hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
-  return true;
-}
-
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band) {
-  switch (band) {
-    case WifiBand::BAND_UNSPECIFIED:
-      return legacy_hal::WIFI_BAND_UNSPECIFIED;
-    case WifiBand::BAND_24GHZ:
-      return legacy_hal::WIFI_BAND_BG;
-    case WifiBand::BAND_5GHZ:
-      return legacy_hal::WIFI_BAND_A;
-    case WifiBand::BAND_5GHZ_DFS:
-      return legacy_hal::WIFI_BAND_A_DFS;
-    case WifiBand::BAND_5GHZ_WITH_DFS:
-      return legacy_hal::WIFI_BAND_A_WITH_DFS;
-    case WifiBand::BAND_24GHZ_5GHZ:
-      return legacy_hal::WIFI_BAND_ABG;
-    case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
-      return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
-  };
-  CHECK(false);
-}
-
-bool convertHidlGscanParamsToLegacy(
-    const StaBackgroundScanParameters& hidl_scan_params,
-    legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
-  if (!legacy_scan_params) {
-    return false;
-  }
-  *legacy_scan_params = {};
-  legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
-  legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
-  legacy_scan_params->report_threshold_percent =
-      hidl_scan_params.reportThresholdPercent;
-  legacy_scan_params->report_threshold_num_scans =
-      hidl_scan_params.reportThresholdNumScans;
-  if (hidl_scan_params.buckets.size() > MAX_BUCKETS) {
-    return false;
-  }
-  legacy_scan_params->num_buckets = hidl_scan_params.buckets.size();
-  for (uint32_t bucket_idx = 0; bucket_idx < hidl_scan_params.buckets.size();
-       bucket_idx++) {
-    const StaBackgroundScanBucketParameters& hidl_bucket_spec =
-        hidl_scan_params.buckets[bucket_idx];
-    legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
-        legacy_scan_params->buckets[bucket_idx];
-    if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
-      return false;
-    }
-    legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
-    legacy_bucket_spec.band =
-        convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
-    legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
-    legacy_bucket_spec.max_period = hidl_bucket_spec.exponentialMaxPeriodInMs;
-    legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
-    legacy_bucket_spec.step_count = hidl_bucket_spec.exponentialStepCount;
-    legacy_bucket_spec.report_events = 0;
-    using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
-    for (const auto flag :
-         {HidlFlag::EACH_SCAN, HidlFlag::FULL_RESULTS, HidlFlag::NO_BATCH}) {
-      if (hidl_bucket_spec.eventReportScheme &
-          static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
-        legacy_bucket_spec.report_events |=
-            convertHidlGscanReportEventFlagToLegacy(flag);
-      }
-    }
-    if (hidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
-      return false;
-    }
-    legacy_bucket_spec.num_channels = hidl_bucket_spec.frequencies.size();
-    for (uint32_t freq_idx = 0; freq_idx < hidl_bucket_spec.frequencies.size();
-         freq_idx++) {
-      legacy_bucket_spec.channels[freq_idx].channel =
-          hidl_bucket_spec.frequencies[freq_idx];
-    }
-  }
-  return true;
-}
-
-bool convertLegacyIeToHidl(
-    const legacy_hal::wifi_information_element& legacy_ie,
-    WifiInformationElement* hidl_ie) {
-  if (!hidl_ie) {
-    return false;
-  }
-  *hidl_ie = {};
-  hidl_ie->id = legacy_ie.id;
-  hidl_ie->data =
-      std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
-  return true;
-}
-
-bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob,
-                               uint32_t ie_blob_len,
-                               std::vector<WifiInformationElement>* hidl_ies) {
-  if (!ie_blob || !hidl_ies) {
-    return false;
-  }
-  *hidl_ies = {};
-  const uint8_t* ies_begin = ie_blob;
-  const uint8_t* ies_end = ie_blob + ie_blob_len;
-  const uint8_t* next_ie = ies_begin;
-  using wifi_ie = legacy_hal::wifi_information_element;
-  constexpr size_t kIeHeaderLen = sizeof(wifi_ie);
-  // Each IE should atleast have the header (i.e |id| & |len| fields).
-  while (next_ie + kIeHeaderLen <= ies_end) {
-    const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
-    uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
-    if (next_ie + curr_ie_len > ies_end) {
-      LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void *)next_ie
-                 << ", Curr IE len: " << curr_ie_len << ", IEs End: " << (void *)ies_end;
-      break;
-    }
-    WifiInformationElement hidl_ie;
-    if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
-      LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id
-                 << ", len: " << legacy_ie.len;
-      break;
-    }
-    hidl_ies->push_back(std::move(hidl_ie));
-    next_ie += curr_ie_len;
-  }
-  // Check if the blob has been fully consumed.
-  if (next_ie != ies_end) {
-    LOG(ERROR) << "Failed to fully parse IE blob. Next IE: " << (void *)next_ie
-               << ", IEs End: " << (void *)ies_end;
-  }
-  return true;
-}
-
-bool convertLegacyGscanResultToHidl(
-    const legacy_hal::wifi_scan_result& legacy_scan_result,
-    bool has_ie_data,
-    StaScanResult* hidl_scan_result) {
-  if (!hidl_scan_result) {
-    return false;
-  }
-  *hidl_scan_result = {};
-  hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
-  hidl_scan_result->ssid = std::vector<uint8_t>(
-      legacy_scan_result.ssid,
-      legacy_scan_result.ssid + strnlen(legacy_scan_result.ssid,
-            sizeof(legacy_scan_result.ssid) - 1));
-  memcpy(hidl_scan_result->bssid.data(),
-         legacy_scan_result.bssid,
-         hidl_scan_result->bssid.size());
-  hidl_scan_result->frequency = legacy_scan_result.channel;
-  hidl_scan_result->rssi = legacy_scan_result.rssi;
-  hidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
-  hidl_scan_result->capability = legacy_scan_result.capability;
-  if (has_ie_data) {
-    std::vector<WifiInformationElement> ies;
-    if (!convertLegacyIeBlobToHidl(
-            reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
-            legacy_scan_result.ie_length,
-            &ies)) {
-      return false;
-    }
-    hidl_scan_result->informationElements = std::move(ies);
-  }
-  return true;
-}
-
-bool convertLegacyCachedGscanResultsToHidl(
-    const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
-    StaScanData* hidl_scan_data) {
-  if (!hidl_scan_data) {
-    return false;
-  }
-  *hidl_scan_data = {};
-  hidl_scan_data->flags = 0;
-  for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
-    if (legacy_cached_scan_result.flags & flag) {
-      hidl_scan_data->flags |=
-          static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
-              convertLegacyGscanDataFlagToHidl(flag));
-    }
-  }
-  hidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
-
-  CHECK(legacy_cached_scan_result.num_results >= 0 &&
-        legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN);
-  std::vector<StaScanResult> hidl_scan_results;
-  for (int32_t result_idx = 0;
-       result_idx < legacy_cached_scan_result.num_results;
-       result_idx++) {
-    StaScanResult hidl_scan_result;
-    if (!convertLegacyGscanResultToHidl(
-            legacy_cached_scan_result.results[result_idx],
-            false,
-            &hidl_scan_result)) {
-      return false;
-    }
-    hidl_scan_results.push_back(hidl_scan_result);
-  }
-  hidl_scan_data->results = std::move(hidl_scan_results);
-  return true;
-}
-
-bool convertLegacyVectorOfCachedGscanResultsToHidl(
-    const std::vector<legacy_hal::wifi_cached_scan_results>&
-        legacy_cached_scan_results,
-    std::vector<StaScanData>* hidl_scan_datas) {
-  if (!hidl_scan_datas) {
-    return false;
-  }
-  *hidl_scan_datas = {};
-  for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
-    StaScanData hidl_scan_data;
-    if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result,
-                                               &hidl_scan_data)) {
-      return false;
-    }
-    hidl_scan_datas->push_back(hidl_scan_data);
-  }
-  return true;
-}
-
-WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(
-    legacy_hal::wifi_tx_packet_fate fate) {
-  switch (fate) {
-    case legacy_hal::TX_PKT_FATE_ACKED:
-      return WifiDebugTxPacketFate::ACKED;
-    case legacy_hal::TX_PKT_FATE_SENT:
-      return WifiDebugTxPacketFate::SENT;
-    case legacy_hal::TX_PKT_FATE_FW_QUEUED:
-      return WifiDebugTxPacketFate::FW_QUEUED;
-    case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
-      return WifiDebugTxPacketFate::FW_DROP_INVALID;
-    case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
-      return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
-    case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
-      return WifiDebugTxPacketFate::FW_DROP_OTHER;
-    case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
-      return WifiDebugTxPacketFate::DRV_QUEUED;
-    case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
-      return WifiDebugTxPacketFate::DRV_DROP_INVALID;
-    case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
-      return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
-    case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
-      return WifiDebugTxPacketFate::DRV_DROP_OTHER;
-  };
-  CHECK(false) << "Unknown legacy fate type: " << fate;
-}
-
-WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToHidl(
-    legacy_hal::wifi_rx_packet_fate fate) {
-  switch (fate) {
-    case legacy_hal::RX_PKT_FATE_SUCCESS:
-      return WifiDebugRxPacketFate::SUCCESS;
-    case legacy_hal::RX_PKT_FATE_FW_QUEUED:
-      return WifiDebugRxPacketFate::FW_QUEUED;
-    case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
-      return WifiDebugRxPacketFate::FW_DROP_FILTER;
-    case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
-      return WifiDebugRxPacketFate::FW_DROP_INVALID;
-    case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
-      return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
-    case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
-      return WifiDebugRxPacketFate::FW_DROP_OTHER;
-    case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
-      return WifiDebugRxPacketFate::DRV_QUEUED;
-    case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
-      return WifiDebugRxPacketFate::DRV_DROP_FILTER;
-    case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
-      return WifiDebugRxPacketFate::DRV_DROP_INVALID;
-    case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
-      return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
-    case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
-      return WifiDebugRxPacketFate::DRV_DROP_OTHER;
-  };
-  CHECK(false) << "Unknown legacy fate type: " << fate;
-}
-
-WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToHidl(
-    legacy_hal::frame_type type) {
-  switch (type) {
-    case legacy_hal::FRAME_TYPE_UNKNOWN:
-      return WifiDebugPacketFateFrameType::UNKNOWN;
-    case legacy_hal::FRAME_TYPE_ETHERNET_II:
-      return WifiDebugPacketFateFrameType::ETHERNET_II;
-    case legacy_hal::FRAME_TYPE_80211_MGMT:
-      return WifiDebugPacketFateFrameType::MGMT_80211;
-  };
-  CHECK(false) << "Unknown legacy frame type: " << type;
-}
-
-bool convertLegacyDebugPacketFateFrameToHidl(
-    const legacy_hal::frame_info& legacy_frame,
-    WifiDebugPacketFateFrameInfo* hidl_frame) {
-  if (!hidl_frame) {
-    return false;
-  }
-  *hidl_frame = {};
-  hidl_frame->frameType =
-      convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
-  hidl_frame->frameLen = legacy_frame.frame_len;
-  hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
-  hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
-  const uint8_t* frame_begin = reinterpret_cast<const uint8_t*>(
-      legacy_frame.frame_content.ethernet_ii_bytes);
-  hidl_frame->frameContent =
-      std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
-  return true;
-}
-
-bool convertLegacyDebugTxPacketFateToHidl(
-    const legacy_hal::wifi_tx_report& legacy_fate,
-    WifiDebugTxPacketFateReport* hidl_fate) {
-  if (!hidl_fate) {
-    return false;
-  }
-  *hidl_fate = {};
-  hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
-  return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
-                                                 &hidl_fate->frameInfo);
-}
-
-bool convertLegacyVectorOfDebugTxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
-    std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
-  if (!hidl_fates) {
-    return false;
-  }
-  *hidl_fates = {};
-  for (const auto& legacy_fate : legacy_fates) {
-    WifiDebugTxPacketFateReport hidl_fate;
-    if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
-      return false;
-    }
-    hidl_fates->push_back(hidl_fate);
-  }
-  return true;
-}
-
-bool convertLegacyDebugRxPacketFateToHidl(
-    const legacy_hal::wifi_rx_report& legacy_fate,
-    WifiDebugRxPacketFateReport* hidl_fate) {
-  if (!hidl_fate) {
-    return false;
-  }
-  *hidl_fate = {};
-  hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
-  return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
-                                                 &hidl_fate->frameInfo);
-}
-
-bool convertLegacyVectorOfDebugRxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
-    std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
-  if (!hidl_fates) {
-    return false;
-  }
-  *hidl_fates = {};
-  for (const auto& legacy_fate : legacy_fates) {
-    WifiDebugRxPacketFateReport hidl_fate;
-    if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
-      return false;
-    }
-    hidl_fates->push_back(hidl_fate);
-  }
-  return true;
-}
-
-bool convertLegacyLinkLayerStatsToHidl(
-    const legacy_hal::LinkLayerStats& legacy_stats,
-    StaLinkLayerStats* hidl_stats) {
-  if (!hidl_stats) {
-    return false;
-  }
-  *hidl_stats = {};
-  // iface legacy_stats conversion.
-  hidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx;
-  hidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
-  hidl_stats->iface.wmeBePktStats.rxMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
-  hidl_stats->iface.wmeBePktStats.txMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
-  hidl_stats->iface.wmeBePktStats.lostMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
-  hidl_stats->iface.wmeBePktStats.retries =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
-  hidl_stats->iface.wmeBkPktStats.rxMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
-  hidl_stats->iface.wmeBkPktStats.txMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
-  hidl_stats->iface.wmeBkPktStats.lostMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
-  hidl_stats->iface.wmeBkPktStats.retries =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
-  hidl_stats->iface.wmeViPktStats.rxMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
-  hidl_stats->iface.wmeViPktStats.txMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
-  hidl_stats->iface.wmeViPktStats.lostMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
-  hidl_stats->iface.wmeViPktStats.retries =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
-  hidl_stats->iface.wmeVoPktStats.rxMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
-  hidl_stats->iface.wmeVoPktStats.txMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
-  hidl_stats->iface.wmeVoPktStats.lostMpdu =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
-  hidl_stats->iface.wmeVoPktStats.retries =
-      legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
-  // radio legacy_stats conversion.
-  std::vector<StaLinkLayerRadioStats> hidl_radios_stats;
-  for (const auto& legacy_radio_stats : legacy_stats.radios) {
-    StaLinkLayerRadioStats hidl_radio_stats;
-    hidl_radio_stats.onTimeInMs = legacy_radio_stats.stats.on_time;
-    hidl_radio_stats.txTimeInMs = legacy_radio_stats.stats.tx_time;
-    hidl_radio_stats.rxTimeInMs = legacy_radio_stats.stats.rx_time;
-    hidl_radio_stats.onTimeInMsForScan = legacy_radio_stats.stats.on_time_scan;
-    hidl_radio_stats.txTimeInMsPerLevel = legacy_radio_stats.tx_time_per_levels;
-    hidl_radios_stats.push_back(hidl_radio_stats);
-  }
-  hidl_stats->radios = hidl_radios_stats;
-  // Timestamp in the HAL wrapper here since it's not provided in the legacy
-  // HAL API.
-  hidl_stats->timeStampInMs = uptimeMillis();
-  return true;
-}
-
-bool convertLegacyRoamingCapabilitiesToHidl(
-    const legacy_hal::wifi_roaming_capabilities& legacy_caps,
-    StaRoamingCapabilities* hidl_caps) {
-  if (!hidl_caps) {
-    return false;
-  }
-  *hidl_caps = {};
-  hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
-  hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
-  return true;
-}
-
-bool convertHidlRoamingConfigToLegacy(
-    const StaRoamingConfig& hidl_config,
-    legacy_hal::wifi_roaming_config* legacy_config) {
-  if (!legacy_config) {
-    return false;
-  }
-  *legacy_config = {};
-  if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
-      hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
-    return false;
-  }
-  legacy_config->num_blacklist_bssid = hidl_config.bssidBlacklist.size();
-  uint32_t i = 0;
-  for (const auto& bssid : hidl_config.bssidBlacklist) {
-    CHECK(bssid.size() == sizeof(legacy_hal::mac_addr));
-    memcpy(legacy_config->blacklist_bssid[i++], bssid.data(), bssid.size());
-  }
-  legacy_config->num_whitelist_ssid = hidl_config.ssidWhitelist.size();
-  i = 0;
-  for (const auto& ssid : hidl_config.ssidWhitelist) {
-    CHECK(ssid.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
-    legacy_config->whitelist_ssid[i].length = ssid.size();
-    memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data(), ssid.size());
-    i++;
-  }
-  return true;
-}
-
-legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
-    StaRoamingState state) {
-  switch (state) {
-    case StaRoamingState::ENABLED:
-      return legacy_hal::ROAMING_ENABLE;
-    case StaRoamingState::DISABLED:
-      return legacy_hal::ROAMING_DISABLE;
-  };
-  CHECK(false);
-}
-
-legacy_hal::NanMatchAlg convertHidlNanMatchAlgToLegacy(NanMatchAlg type) {
-  switch (type) {
-    case NanMatchAlg::MATCH_ONCE:
-      return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
-    case NanMatchAlg::MATCH_CONTINUOUS:
-      return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
-    case NanMatchAlg::MATCH_NEVER:
-      return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
-  }
-  CHECK(false);
-}
-
-legacy_hal::NanPublishType convertHidlNanPublishTypeToLegacy(NanPublishType type) {
-  switch (type) {
-    case NanPublishType::UNSOLICITED:
-      return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
-    case NanPublishType::SOLICITED:
-      return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
-    case NanPublishType::UNSOLICITED_SOLICITED:
-      return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
-  }
-  CHECK(false);
-}
-
-legacy_hal::NanTxType convertHidlNanTxTypeToLegacy(NanTxType type) {
-  switch (type) {
-    case NanTxType::BROADCAST:
-      return legacy_hal::NAN_TX_TYPE_BROADCAST;
-    case NanTxType::UNICAST:
-      return legacy_hal::NAN_TX_TYPE_UNICAST;
-  }
-  CHECK(false);
-}
-
-legacy_hal::NanSubscribeType convertHidlNanSubscribeTypeToLegacy(NanSubscribeType type) {
-  switch (type) {
-    case NanSubscribeType::PASSIVE:
-      return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
-    case NanSubscribeType::ACTIVE:
-      return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
-  }
-  CHECK(false);
-}
-
-legacy_hal::NanSRFType convertHidlNanSrfTypeToLegacy(NanSrfType type) {
-  switch (type) {
-    case NanSrfType::BLOOM_FILTER:
-      return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
-    case NanSrfType::PARTIAL_MAC_ADDR:
-      return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
-  }
-  CHECK(false);
-}
-
-legacy_hal::NanDataPathChannelCfg convertHidlNanDataPathChannelCfgToLegacy(
-    NanDataPathChannelCfg type) {
-  switch (type) {
-    case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED:
-      return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED;
-    case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP:
-      return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP;
-    case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP:
-      return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP;
-  }
-  CHECK(false);
-}
-
-NanStatusType convertLegacyNanStatusTypeToHidl(
-    legacy_hal::NanStatusType type) {
-  switch (type) {
-    case legacy_hal::NAN_STATUS_SUCCESS:
-      return NanStatusType::SUCCESS;
-    case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
-      return NanStatusType::INTERNAL_FAILURE;
-    case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
-      return NanStatusType::PROTOCOL_FAILURE;
-    case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
-      return NanStatusType::INVALID_SESSION_ID;
-    case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
-      return NanStatusType::NO_RESOURCES_AVAILABLE;
-    case legacy_hal::NAN_STATUS_INVALID_PARAM:
-      return NanStatusType::INVALID_ARGS;
-    case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
-      return NanStatusType::INVALID_PEER_ID;
-    case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
-      return NanStatusType::INVALID_NDP_ID;
-    case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
-      return NanStatusType::NAN_NOT_ALLOWED;
-    case legacy_hal::NAN_STATUS_NO_OTA_ACK:
-      return NanStatusType::NO_OTA_ACK;
-    case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
-      return NanStatusType::ALREADY_ENABLED;
-    case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
-      return NanStatusType::FOLLOWUP_TX_QUEUE_FULL;
-    case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
-      return NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
-  }
-  CHECK(false);
-}
-
-void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
-    WifiNanStatus* wifiNanStatus) {
-  wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(type);
-  wifiNanStatus->description = safeConvertChar(str, max_len);
-}
-
-bool convertHidlNanEnableRequestToLegacy(
-    const NanEnableRequest& hidl_request,
-    legacy_hal::NanEnableRequest* legacy_request) {
-  if (!legacy_request) {
-    LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: null legacy_request";
-    return false;
-  }
-  *legacy_request = {};
-
-  legacy_request->config_2dot4g_support = 1;
-  legacy_request->support_2dot4g_val = hidl_request.operateInBand[
-        (size_t) NanBandIndex::NAN_BAND_24GHZ];
-  legacy_request->config_support_5g = 1;
-  legacy_request->support_5g_val = hidl_request.operateInBand[(size_t) NanBandIndex::NAN_BAND_5GHZ];
-  legacy_request->config_hop_count_limit = 1;
-  legacy_request->hop_count_limit_val = hidl_request.hopCountMax;
-  legacy_request->master_pref = hidl_request.configParams.masterPref;
-  legacy_request->discovery_indication_cfg = 0;
-  legacy_request->discovery_indication_cfg |=
-        hidl_request.configParams.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
-  legacy_request->discovery_indication_cfg |=
-        hidl_request.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
-  legacy_request->discovery_indication_cfg |=
-        hidl_request.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
-  legacy_request->config_sid_beacon = 1;
-  if (hidl_request.configParams.numberOfPublishServiceIdsInBeacon > 127) {
-    LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: numberOfPublishServiceIdsInBeacon > 127";
-    return false;
-  }
-  legacy_request->sid_beacon_val =
-        (hidl_request.configParams.includePublishServiceIdsInBeacon ? 0x1 : 0x0)
-            | (hidl_request.configParams.numberOfPublishServiceIdsInBeacon << 1);
-  legacy_request->config_subscribe_sid_beacon = 1;
-  if (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon > 127) {
-    LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: numberOfSubscribeServiceIdsInBeacon > 127";
-    return false;
-  }
-  legacy_request->subscribe_sid_beacon_val =
-        (hidl_request.configParams.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0)
-            | (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
-  legacy_request->config_rssi_window_size = 1;
-  legacy_request->rssi_window_size_val = hidl_request.configParams.rssiWindowSize;
-  legacy_request->config_disc_mac_addr_randomization = 1;
-  legacy_request->disc_mac_addr_rand_interval_sec =
-        hidl_request.configParams.macAddressRandomizationIntervalSec;
-  legacy_request->config_2dot4g_rssi_close = 1;
-  if (hidl_request.configParams.bandSpecificConfig.size() != 2) {
-    LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: bandSpecificConfig.size() != 2";
-    return false;
-  }
-  legacy_request->rssi_close_2dot4g_val =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
-  legacy_request->config_2dot4g_rssi_middle = 1;
-  legacy_request->rssi_middle_2dot4g_val =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
-  legacy_request->config_2dot4g_rssi_proximity = 1;
-  legacy_request->rssi_proximity_2dot4g_val =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiCloseProximity;
-  legacy_request->config_scan_params = 1;
-  legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_24GHZ].dwellTimeMs;
-  legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_24GHZ].scanPeriodSec;
-  legacy_request->config_dw.config_2dot4g_dw_band = hidl_request.configParams
-        .bandSpecificConfig[(size_t) NanBandIndex::NAN_BAND_24GHZ].validDiscoveryWindowIntervalVal;
-  legacy_request->config_dw.dw_2dot4g_interval_val = hidl_request.configParams
-        .bandSpecificConfig[(size_t) NanBandIndex::NAN_BAND_24GHZ].discoveryWindowIntervalVal;
-  legacy_request->config_5g_rssi_close = 1;
-  legacy_request->rssi_close_5g_val =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
-  legacy_request->config_5g_rssi_middle = 1;
-  legacy_request->rssi_middle_5g_val =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
-  legacy_request->config_5g_rssi_close_proximity = 1;
-  legacy_request->rssi_close_proximity_5g_val =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiCloseProximity;
-  legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
-  legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
-  legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
-  legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.configParams.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
-  legacy_request->config_dw.config_5g_dw_band = hidl_request.configParams
-        .bandSpecificConfig[(size_t) NanBandIndex::NAN_BAND_5GHZ].validDiscoveryWindowIntervalVal;
-  legacy_request->config_dw.dw_5g_interval_val = hidl_request.configParams
-        .bandSpecificConfig[(size_t) NanBandIndex::NAN_BAND_5GHZ].discoveryWindowIntervalVal;
-  if (hidl_request.debugConfigs.validClusterIdVals) {
-    legacy_request->cluster_low = hidl_request.debugConfigs.clusterIdBottomRangeVal;
-    legacy_request->cluster_high = hidl_request.debugConfigs.clusterIdTopRangeVal;
-  } else { // need 'else' since not configurable in legacy HAL
-    legacy_request->cluster_low = 0x0000;
-    legacy_request->cluster_high = 0xFFFF;
-  }
-  legacy_request->config_intf_addr = hidl_request.debugConfigs.validIntfAddrVal;
-  memcpy(legacy_request->intf_addr_val, hidl_request.debugConfigs.intfAddrVal.data(), 6);
-  legacy_request->config_oui = hidl_request.debugConfigs.validOuiVal;
-  legacy_request->oui_val = hidl_request.debugConfigs.ouiVal;
-  legacy_request->config_random_factor_force = hidl_request.debugConfigs.validRandomFactorForceVal;
-  legacy_request->random_factor_force_val = hidl_request.debugConfigs.randomFactorForceVal;
-  legacy_request->config_hop_count_force = hidl_request.debugConfigs.validHopCountForceVal;
-  legacy_request->hop_count_force_val = hidl_request.debugConfigs.hopCountForceVal;
-  legacy_request->config_24g_channel = hidl_request.debugConfigs.validDiscoveryChannelVal;
-  legacy_request->channel_24g_val =
-        hidl_request.debugConfigs.discoveryChannelMhzVal[(size_t) NanBandIndex::NAN_BAND_24GHZ];
-  legacy_request->config_5g_channel = hidl_request.debugConfigs.validDiscoveryChannelVal;
-  legacy_request->channel_5g_val = hidl_request.debugConfigs
-        .discoveryChannelMhzVal[(size_t) NanBandIndex::NAN_BAND_5GHZ];
-  legacy_request->config_2dot4g_beacons = hidl_request.debugConfigs.validUseBeaconsInBandVal;
-  legacy_request->beacon_2dot4g_val = hidl_request.debugConfigs
-        .useBeaconsInBandVal[(size_t) NanBandIndex::NAN_BAND_24GHZ];
-  legacy_request->config_5g_beacons = hidl_request.debugConfigs.validUseBeaconsInBandVal;
-  legacy_request->beacon_5g_val = hidl_request.debugConfigs
-        .useBeaconsInBandVal[(size_t) NanBandIndex::NAN_BAND_5GHZ];
-  legacy_request->config_2dot4g_sdf = hidl_request.debugConfigs.validUseSdfInBandVal;
-  legacy_request->sdf_2dot4g_val = hidl_request.debugConfigs
-        .useSdfInBandVal[(size_t) NanBandIndex::NAN_BAND_24GHZ];
-  legacy_request->config_5g_sdf = hidl_request.debugConfigs.validUseSdfInBandVal;
-  legacy_request->sdf_5g_val = hidl_request.debugConfigs
-        .useSdfInBandVal[(size_t) NanBandIndex::NAN_BAND_5GHZ];
-
-  return true;
-}
-
-bool convertHidlNanPublishRequestToLegacy(
-    const NanPublishRequest& hidl_request,
-    legacy_hal::NanPublishRequest* legacy_request) {
-  if (!legacy_request) {
-    LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: null legacy_request";
-    return false;
-  }
-  *legacy_request = {};
-
-  legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
-  legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
-  legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
-  legacy_request->publish_count = hidl_request.baseConfigs.discoveryCount;
-  legacy_request->service_name_len = hidl_request.baseConfigs.serviceName.size();
-  if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-    LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_name_len too large";
-    return false;
-  }
-  memcpy(legacy_request->service_name, hidl_request.baseConfigs.serviceName.data(),
-        legacy_request->service_name_len);
-  legacy_request->publish_match_indicator =
-        convertHidlNanMatchAlgToLegacy(hidl_request.baseConfigs.discoveryMatchIndicator);
-  legacy_request->service_specific_info_len = hidl_request.baseConfigs.serviceSpecificInfo.size();
-  if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-    LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_specific_info_len too large";
-    return false;
-  }
-  memcpy(legacy_request->service_specific_info,
-        hidl_request.baseConfigs.serviceSpecificInfo.data(),
-        legacy_request->service_specific_info_len);
-  legacy_request->sdea_service_specific_info_len =
-        hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
-  if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-    LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: sdea_service_specific_info_len too large";
-    return false;
-  }
-  memcpy(legacy_request->sdea_service_specific_info,
-        hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
-        legacy_request->sdea_service_specific_info_len);
-  legacy_request->rx_match_filter_len = hidl_request.baseConfigs.rxMatchFilter.size();
-  if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-    LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: rx_match_filter_len too large";
-    return false;
-  }
-  memcpy(legacy_request->rx_match_filter,
-        hidl_request.baseConfigs.rxMatchFilter.data(),
-        legacy_request->rx_match_filter_len);
-  legacy_request->tx_match_filter_len = hidl_request.baseConfigs.txMatchFilter.size();
-  if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-    LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: tx_match_filter_len too large";
-    return false;
-  }
-  memcpy(legacy_request->tx_match_filter,
-        hidl_request.baseConfigs.txMatchFilter.data(),
-        legacy_request->tx_match_filter_len);
-  legacy_request->rssi_threshold_flag = hidl_request.baseConfigs.useRssiThreshold;
-  legacy_request->recv_indication_cfg = 0;
-  legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0;
-  legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
-  legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
-  legacy_request->recv_indication_cfg |= 0x8;
-  legacy_request->cipher_type = (unsigned int) hidl_request.baseConfigs.securityConfig.cipherType;
-  if (hidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PMK) {
-    legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-    legacy_request->key_info.body.pmk_info.pmk_len =
-        hidl_request.baseConfigs.securityConfig.pmk.size();
-    if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
-      LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: invalid pmk_len";
-      return false;
-    }
-    memcpy(legacy_request->key_info.body.pmk_info.pmk,
-          hidl_request.baseConfigs.securityConfig.pmk.data(),
-          legacy_request->key_info.body.pmk_info.pmk_len);
-  }
-  if (hidl_request.baseConfigs.securityConfig.securityType
-        == NanDataPathSecurityType::PASSPHRASE) {
-    legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-    legacy_request->key_info.body.passphrase_info.passphrase_len =
-        hidl_request.baseConfigs.securityConfig.passphrase.size();
-    if (legacy_request->key_info.body.passphrase_info.passphrase_len
-            < NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-      LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: passphrase_len too small";
-      return false;
-    }
-    if (legacy_request->key_info.body.passphrase_info.passphrase_len
-            > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-      LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: passphrase_len too large";
-      return false;
-    }
-    memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-          hidl_request.baseConfigs.securityConfig.passphrase.data(),
-          legacy_request->key_info.body.passphrase_info.passphrase_len);
-  }
-  legacy_request->sdea_params.security_cfg = (hidl_request.baseConfigs.securityConfig.securityType
-        != NanDataPathSecurityType::OPEN) ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-  legacy_request->sdea_params.ranging_state = hidl_request.baseConfigs.rangingRequired ?
-        legacy_hal::NAN_RANGING_ENABLE : legacy_hal::NAN_RANGING_DISABLE;
-  legacy_request->ranging_cfg.ranging_interval_msec = hidl_request.baseConfigs.rangingIntervalMsec;
-  legacy_request->ranging_cfg.config_ranging_indications =
-        hidl_request.baseConfigs.configRangingIndications;
-  legacy_request->ranging_cfg.distance_ingress_cm = hidl_request.baseConfigs.distanceIngressCm;
-  legacy_request->ranging_cfg.distance_egress_cm = hidl_request.baseConfigs.distanceEgressCm;
-  legacy_request->ranging_auto_response = hidl_request.baseConfigs.rangingRequired ?
-        legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
-  legacy_request->sdea_params.range_report = legacy_hal::NAN_DISABLE_RANGE_REPORT;
-  legacy_request->publish_type = convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
-  legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
-  legacy_request->service_responder_policy = hidl_request.autoAcceptDataPathRequests ?
-        legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
-
-  return true;
-}
-
-bool convertHidlNanSubscribeRequestToLegacy(
-    const NanSubscribeRequest& hidl_request,
-    legacy_hal::NanSubscribeRequest* legacy_request) {
-  if (!legacy_request) {
-    LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
-    return false;
-  }
-  *legacy_request = {};
-
-  legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
-  legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
-  legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
-  legacy_request->subscribe_count = hidl_request.baseConfigs.discoveryCount;
-  legacy_request->service_name_len = hidl_request.baseConfigs.serviceName.size();
-  if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-    LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: service_name_len too large";
-    return false;
-  }
-  memcpy(legacy_request->service_name, hidl_request.baseConfigs.serviceName.data(),
-        legacy_request->service_name_len);
-  legacy_request->subscribe_match_indicator =
-        convertHidlNanMatchAlgToLegacy(hidl_request.baseConfigs.discoveryMatchIndicator);
-  legacy_request->service_specific_info_len = hidl_request.baseConfigs.serviceSpecificInfo.size();
-  if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-    LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: service_specific_info_len too large";
-    return false;
-  }
-  memcpy(legacy_request->service_specific_info,
-        hidl_request.baseConfigs.serviceSpecificInfo.data(),
-        legacy_request->service_specific_info_len);
-  legacy_request->sdea_service_specific_info_len =
-        hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
-  if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-    LOG(ERROR) <<
-        "convertHidlNanSubscribeRequestToLegacy: sdea_service_specific_info_len too large";
-    return false;
-  }
-  memcpy(legacy_request->sdea_service_specific_info,
-        hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
-        legacy_request->sdea_service_specific_info_len);
-  legacy_request->rx_match_filter_len = hidl_request.baseConfigs.rxMatchFilter.size();
-  if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-    LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: rx_match_filter_len too large";
-    return false;
-  }
-  memcpy(legacy_request->rx_match_filter,
-        hidl_request.baseConfigs.rxMatchFilter.data(),
-        legacy_request->rx_match_filter_len);
-  legacy_request->tx_match_filter_len = hidl_request.baseConfigs.txMatchFilter.size();
-  if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
-    LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: tx_match_filter_len too large";
-    return false;
-  }
-  memcpy(legacy_request->tx_match_filter,
-        hidl_request.baseConfigs.txMatchFilter.data(),
-        legacy_request->tx_match_filter_len);
-  legacy_request->rssi_threshold_flag = hidl_request.baseConfigs.useRssiThreshold;
-  legacy_request->recv_indication_cfg = 0;
-  legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1 : 0x0;
-  legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
-  legacy_request->recv_indication_cfg |=
-        hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
-  legacy_request->cipher_type = (unsigned int) hidl_request.baseConfigs.securityConfig.cipherType;
-  if (hidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PMK) {
-    legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-    legacy_request->key_info.body.pmk_info.pmk_len =
-        hidl_request.baseConfigs.securityConfig.pmk.size();
-    if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
-      LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: invalid pmk_len";
-      return false;
-    }
-    memcpy(legacy_request->key_info.body.pmk_info.pmk,
-          hidl_request.baseConfigs.securityConfig.pmk.data(),
-          legacy_request->key_info.body.pmk_info.pmk_len);
-  }
-  if (hidl_request.baseConfigs.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
-    legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-    legacy_request->key_info.body.passphrase_info.passphrase_len =
-        hidl_request.baseConfigs.securityConfig.passphrase.size();
-    if (legacy_request->key_info.body.passphrase_info.passphrase_len
-            < NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-      LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: passphrase_len too small";
-      return false;
-    }
-    if (legacy_request->key_info.body.passphrase_info.passphrase_len
-            > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-      LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: passphrase_len too large";
-      return false;
-    }
-    memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-          hidl_request.baseConfigs.securityConfig.passphrase.data(),
-          legacy_request->key_info.body.passphrase_info.passphrase_len);
-  }
-  legacy_request->sdea_params.security_cfg = (hidl_request.baseConfigs.securityConfig.securityType
-          != NanDataPathSecurityType::OPEN) ? legacy_hal::NAN_DP_CONFIG_SECURITY
-              : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-  legacy_request->sdea_params.ranging_state = hidl_request.baseConfigs.rangingRequired ?
-        legacy_hal::NAN_RANGING_ENABLE : legacy_hal::NAN_RANGING_DISABLE;
-  legacy_request->ranging_cfg.ranging_interval_msec = hidl_request.baseConfigs.rangingIntervalMsec;
-  legacy_request->ranging_cfg.config_ranging_indications =
-        hidl_request.baseConfigs.configRangingIndications;
-  legacy_request->ranging_cfg.distance_ingress_cm = hidl_request.baseConfigs.distanceIngressCm;
-  legacy_request->ranging_cfg.distance_egress_cm = hidl_request.baseConfigs.distanceEgressCm;
-  legacy_request->ranging_auto_response = hidl_request.baseConfigs.rangingRequired ?
-        legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
-  legacy_request->sdea_params.range_report = legacy_hal::NAN_DISABLE_RANGE_REPORT;
-  legacy_request->subscribe_type = convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
-  legacy_request->serviceResponseFilter = convertHidlNanSrfTypeToLegacy(hidl_request.srfType);
-  legacy_request->serviceResponseInclude = hidl_request.srfRespondIfInAddressSet ?
-        legacy_hal::NAN_SRF_INCLUDE_RESPOND : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
-  legacy_request->useServiceResponseFilter = hidl_request.shouldUseSrf ?
-        legacy_hal::NAN_USE_SRF : legacy_hal::NAN_DO_NOT_USE_SRF;
-  legacy_request->ssiRequiredForMatchIndication = hidl_request.isSsiRequiredForMatch ?
-        legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
-  legacy_request->num_intf_addr_present = hidl_request.intfAddr.size();
-  if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
-    LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: num_intf_addr_present - too many";
-    return false;
-  }
-  for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
-    memcpy(legacy_request->intf_addr[i], hidl_request.intfAddr[i].data(), 6);
-  }
-
-  return true;
-}
-
-bool convertHidlNanTransmitFollowupRequestToLegacy(
-    const NanTransmitFollowupRequest& hidl_request,
-    legacy_hal::NanTransmitFollowupRequest* legacy_request) {
-  if (!legacy_request) {
-    LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: legacy_request is null";
-    return false;
-  }
-  *legacy_request = {};
-
-  legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
-  legacy_request->requestor_instance_id = hidl_request.peerId;
-  memcpy(legacy_request->addr, hidl_request.addr.data(), 6);
-  legacy_request->priority = hidl_request.isHighPriority ?
-        legacy_hal::NAN_TX_PRIORITY_HIGH : legacy_hal::NAN_TX_PRIORITY_NORMAL;
-  legacy_request->dw_or_faw = hidl_request.shouldUseDiscoveryWindow ?
-        legacy_hal::NAN_TRANSMIT_IN_DW : legacy_hal::NAN_TRANSMIT_IN_FAW;
-  legacy_request->service_specific_info_len = hidl_request.serviceSpecificInfo.size();
-  if (legacy_request->service_specific_info_len > NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
-    LOG(ERROR) <<
-        "convertHidlNanTransmitFollowupRequestToLegacy: service_specific_info_len too large";
-    return false;
-  }
-  memcpy(legacy_request->service_specific_info,
-        hidl_request.serviceSpecificInfo.data(),
-        legacy_request->service_specific_info_len);
-  legacy_request->sdea_service_specific_info_len = hidl_request.extendedServiceSpecificInfo.size();
-  if (legacy_request->sdea_service_specific_info_len > NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
-    LOG(ERROR) <<
-        "convertHidlNanTransmitFollowupRequestToLegacy: sdea_service_specific_info_len too large";
-    return false;
-  }
-  memcpy(legacy_request->sdea_service_specific_info,
-        hidl_request.extendedServiceSpecificInfo.data(),
-        legacy_request->sdea_service_specific_info_len);
-  legacy_request->recv_indication_cfg = hidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
-
-  return true;
-}
-
-bool convertHidlNanConfigRequestToLegacy(
-    const NanConfigRequest& hidl_request,
-    legacy_hal::NanConfigRequest* legacy_request) {
-  if (!legacy_request) {
-    LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
-    return false;
-  }
-  *legacy_request = {};
-
-  // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown defaults
-  legacy_request->master_pref = hidl_request.masterPref;
-  legacy_request->discovery_indication_cfg = 0;
-  legacy_request->discovery_indication_cfg |=
-        hidl_request.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
-  legacy_request->discovery_indication_cfg |=
-        hidl_request.disableStartedClusterIndication ? 0x2 : 0x0;
-  legacy_request->discovery_indication_cfg |=
-        hidl_request.disableJoinedClusterIndication ? 0x4 : 0x0;
-  legacy_request->config_sid_beacon = 1;
-  if (hidl_request.numberOfPublishServiceIdsInBeacon > 127) {
-    LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: numberOfPublishServiceIdsInBeacon > 127";
-    return false;
-  }
-  legacy_request->sid_beacon = (hidl_request.includePublishServiceIdsInBeacon ? 0x1 : 0x0)
-        | (hidl_request.numberOfPublishServiceIdsInBeacon << 1);
-  legacy_request->config_subscribe_sid_beacon = 1;
-  if (hidl_request.numberOfSubscribeServiceIdsInBeacon > 127) {
-    LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: numberOfSubscribeServiceIdsInBeacon > 127";
-    return false;
-  }
-  legacy_request->subscribe_sid_beacon_val =
-        (hidl_request.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0)
-            | (hidl_request.numberOfSubscribeServiceIdsInBeacon << 1);
-  legacy_request->config_rssi_window_size = 1;
-  legacy_request->rssi_window_size_val = hidl_request.rssiWindowSize;
-  legacy_request->config_disc_mac_addr_randomization = 1;
-  legacy_request->disc_mac_addr_rand_interval_sec =
-        hidl_request.macAddressRandomizationIntervalSec;
-  /* TODO : missing
-  legacy_request->config_2dot4g_rssi_close = 1;
-  legacy_request->rssi_close_2dot4g_val =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
-  legacy_request->config_2dot4g_rssi_middle = 1;
-  legacy_request->rssi_middle_2dot4g_val =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
-  legacy_request->config_2dot4g_rssi_proximity = 1;
-  legacy_request->rssi_proximity_2dot4g_val =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiCloseProximity;
-  */
-  legacy_request->config_scan_params = 1;
-  legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_24GHZ].dwellTimeMs;
-  legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_24GHZ].scanPeriodSec;
-  legacy_request->config_dw.config_2dot4g_dw_band = hidl_request
-        .bandSpecificConfig[(size_t) NanBandIndex::NAN_BAND_24GHZ].validDiscoveryWindowIntervalVal;
-  legacy_request->config_dw.dw_2dot4g_interval_val = hidl_request
-        .bandSpecificConfig[(size_t) NanBandIndex::NAN_BAND_24GHZ].discoveryWindowIntervalVal;
-  /* TODO: missing
-  legacy_request->config_5g_rssi_close = 1;
-  legacy_request->rssi_close_5g_val =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
-  legacy_request->config_5g_rssi_middle = 1;
-  legacy_request->rssi_middle_5g_val =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
-  */
-  legacy_request->config_5g_rssi_close_proximity = 1;
-  legacy_request->rssi_close_proximity_5g_val =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiCloseProximity;
-  legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
-  legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
-  legacy_request->scan_params_val.dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].dwellTimeMs;
-  legacy_request->scan_params_val.scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
-        hidl_request.bandSpecificConfig[
-            (size_t) NanBandIndex::NAN_BAND_5GHZ].scanPeriodSec;
-  legacy_request->config_dw.config_5g_dw_band = hidl_request
-        .bandSpecificConfig[(size_t) NanBandIndex::NAN_BAND_5GHZ].validDiscoveryWindowIntervalVal;
-  legacy_request->config_dw.dw_5g_interval_val = hidl_request
-        .bandSpecificConfig[(size_t) NanBandIndex::NAN_BAND_5GHZ].discoveryWindowIntervalVal;
-
-  return true;
-}
-
-bool convertHidlNanDataPathInitiatorRequestToLegacy(
-    const NanInitiateDataPathRequest& hidl_request,
-    legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
-  if (!legacy_request) {
-    LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: legacy_request is null";
-    return false;
-  }
-  *legacy_request = {};
-
-  legacy_request->requestor_instance_id = hidl_request.peerId;
-  memcpy(legacy_request->peer_disc_mac_addr, hidl_request.peerDiscMacAddr.data(), 6);
-  legacy_request->channel_request_type =
-        convertHidlNanDataPathChannelCfgToLegacy(hidl_request.channelRequestType);
-  legacy_request->channel = hidl_request.channel;
-  strcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str());
-  legacy_request->ndp_cfg.security_cfg = (hidl_request.securityConfig.securityType
-        != NanDataPathSecurityType::OPEN) ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-  legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
-  if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
-    LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: ndp_app_info_len too large";
-    return false;
-  }
-  memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
-        legacy_request->app_info.ndp_app_info_len);
-  legacy_request->cipher_type = (unsigned int) hidl_request.securityConfig.cipherType;
-  if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
-    legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-    legacy_request->key_info.body.pmk_info.pmk_len = hidl_request.securityConfig.pmk.size();
-    if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
-      LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: invalid pmk_len";
-      return false;
-    }
-    memcpy(legacy_request->key_info.body.pmk_info.pmk,
-          hidl_request.securityConfig.pmk.data(),
-          legacy_request->key_info.body.pmk_info.pmk_len);
-  }
-  if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
-    legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-    legacy_request->key_info.body.passphrase_info.passphrase_len =
-        hidl_request.securityConfig.passphrase.size();
-    if (legacy_request->key_info.body.passphrase_info.passphrase_len
-            < NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-      LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: passphrase_len too small";
-      return false;
-    }
-    if (legacy_request->key_info.body.passphrase_info.passphrase_len
-            > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-      LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: passphrase_len too large";
-      return false;
-    }
-    memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-          hidl_request.securityConfig.passphrase.data(),
-          legacy_request->key_info.body.passphrase_info.passphrase_len);
-  }
-  legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
-  if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-    LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: service_name_len too large";
-    return false;
-  }
-  memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
-        legacy_request->service_name_len);
-
-  return true;
-}
-
-bool convertHidlNanDataPathIndicationResponseToLegacy(
-    const NanRespondToDataPathIndicationRequest& hidl_request,
-    legacy_hal::NanDataPathIndicationResponse* legacy_request) {
-  if (!legacy_request) {
-    LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: legacy_request is null";
-    return false;
-  }
-  *legacy_request = {};
-
-  legacy_request->rsp_code = hidl_request.acceptRequest ?
-        legacy_hal::NAN_DP_REQUEST_ACCEPT : legacy_hal::NAN_DP_REQUEST_REJECT;
-  legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
-  strcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str());
-  legacy_request->ndp_cfg.security_cfg = (hidl_request.securityConfig.securityType
-        != NanDataPathSecurityType::OPEN) ? legacy_hal::NAN_DP_CONFIG_SECURITY
-            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
-  legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
-  if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
-    LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: ndp_app_info_len too large";
-    return false;
-  }
-  memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
-        legacy_request->app_info.ndp_app_info_len);
-  legacy_request->cipher_type = (unsigned int) hidl_request.securityConfig.cipherType;
-  if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PMK) {
-    legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
-    legacy_request->key_info.body.pmk_info.pmk_len = hidl_request.securityConfig.pmk.size();
-    if (legacy_request->key_info.body.pmk_info.pmk_len != NAN_PMK_INFO_LEN) {
-      LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: invalid pmk_len";
-      return false;
-    }
-    memcpy(legacy_request->key_info.body.pmk_info.pmk,
-          hidl_request.securityConfig.pmk.data(),
-          legacy_request->key_info.body.pmk_info.pmk_len);
-  }
-  if (hidl_request.securityConfig.securityType == NanDataPathSecurityType::PASSPHRASE) {
-    legacy_request->key_info.key_type = legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
-    legacy_request->key_info.body.passphrase_info.passphrase_len =
-        hidl_request.securityConfig.passphrase.size();
-    if (legacy_request->key_info.body.passphrase_info.passphrase_len
-            < NAN_SECURITY_MIN_PASSPHRASE_LEN) {
-      LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: passphrase_len too small";
-      return false;
-    }
-    if (legacy_request->key_info.body.passphrase_info.passphrase_len
-            > NAN_SECURITY_MAX_PASSPHRASE_LEN) {
-      LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: passphrase_len too large";
-      return false;
-    }
-    memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
-          hidl_request.securityConfig.passphrase.data(),
-          legacy_request->key_info.body.passphrase_info.passphrase_len);
-  }
-  legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
-  if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
-    LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: service_name_len too large";
-    return false;
-  }
-  memcpy(legacy_request->service_name, hidl_request.serviceNameOutOfBand.data(),
-        legacy_request->service_name_len);
-
-  return true;
-}
-
-bool convertLegacyNanResponseHeaderToHidl(
-    const legacy_hal::NanResponseMsg& legacy_response,
-    WifiNanStatus* wifiNanStatus) {
-  if (!wifiNanStatus) {
-    LOG(ERROR) << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
-    return false;
-  }
-  *wifiNanStatus = {};
-
-  convertToWifiNanStatus(legacy_response.status, legacy_response.nan_error,
-        sizeof(legacy_response.nan_error), wifiNanStatus);
-  return true;
-}
-
-bool convertLegacyNanCapabilitiesResponseToHidl(
-    const legacy_hal::NanCapabilities& legacy_response,
-    NanCapabilities* hidl_response) {
-  if (!hidl_response) {
-    LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: hidl_response is null";
-    return false;
-  }
-  *hidl_response = {};
-
-  hidl_response->maxConcurrentClusters = legacy_response.max_concurrent_nan_clusters;
-  hidl_response->maxPublishes = legacy_response.max_publishes;
-  hidl_response->maxSubscribes = legacy_response.max_subscribes;
-  hidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
-  hidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
-  hidl_response->maxTotalMatchFilterLen = legacy_response.max_total_match_filter_len;
-  hidl_response->maxServiceSpecificInfoLen = legacy_response.max_service_specific_info_len;
-  hidl_response->maxExtendedServiceSpecificInfoLen =
-    legacy_response.max_sdea_service_specific_info_len;
-  hidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
-  hidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
-  hidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
-  hidl_response->maxQueuedTransmitFollowupMsgs = legacy_response.max_queued_transmit_followup_msgs;
-  hidl_response->maxSubscribeInterfaceAddresses = legacy_response.max_subscribe_address;
-  hidl_response->supportedCipherSuites = legacy_response.cipher_suites_supported;
-
-  return true;
-}
-
-bool convertLegacyNanMatchIndToHidl(
-    const legacy_hal::NanMatchInd& legacy_ind,
-    NanMatchInd* hidl_ind) {
-  if (!hidl_ind) {
-    LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
-    return false;
-  }
-  *hidl_ind = {};
-
-  hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
-  hidl_ind->peerId = legacy_ind.requestor_instance_id;
-  hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
-  hidl_ind->serviceSpecificInfo = std::vector<uint8_t>(legacy_ind.service_specific_info,
-        legacy_ind.service_specific_info + legacy_ind.service_specific_info_len);
-  hidl_ind->extendedServiceSpecificInfo = std::vector<uint8_t>(
-        legacy_ind.sdea_service_specific_info,
-        legacy_ind.sdea_service_specific_info + legacy_ind.sdea_service_specific_info_len);
-  hidl_ind->matchFilter = std::vector<uint8_t>(legacy_ind.sdf_match_filter,
-        legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
-  hidl_ind->matchOccuredInBeaconFlag = legacy_ind.match_occured_flag == 1;
-  hidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
-  hidl_ind->rssiValue = legacy_ind.rssi_value;
-  hidl_ind->peerCipherType = (NanCipherSuiteType) legacy_ind.peer_cipher_type;
-  hidl_ind->peerRequiresSecurityEnabledInNdp =
-        legacy_ind.peer_sdea_params.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
-  hidl_ind->peerRequiresRanging =
-        legacy_ind.peer_sdea_params.ranging_state == legacy_hal::NAN_RANGING_ENABLE;
-  hidl_ind->rangingMeasurementInCm = legacy_ind.range_info.range_measurement_cm;
-  hidl_ind->rangingIndicationType = legacy_ind.range_info.ranging_event_type;
-
-  return true;
-}
-
-bool convertLegacyNanFollowupIndToHidl(
-    const legacy_hal::NanFollowupInd& legacy_ind,
-    NanFollowupReceivedInd* hidl_ind) {
-  if (!hidl_ind) {
-    LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
-    return false;
-  }
-  *hidl_ind = {};
-
-  hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
-  hidl_ind->peerId = legacy_ind.requestor_instance_id;
-  hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
-  hidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
-  hidl_ind->serviceSpecificInfo = std::vector<uint8_t>(legacy_ind.service_specific_info,
-        legacy_ind.service_specific_info + legacy_ind.service_specific_info_len);
-  hidl_ind->extendedServiceSpecificInfo = std::vector<uint8_t>(
-        legacy_ind.sdea_service_specific_info,
-        legacy_ind.sdea_service_specific_info + legacy_ind.sdea_service_specific_info_len);
-
-  return true;
-}
-
-bool convertLegacyNanDataPathRequestIndToHidl(
-    const legacy_hal::NanDataPathRequestInd& legacy_ind,
-    NanDataPathRequestInd* hidl_ind) {
-  if (!hidl_ind) {
-    LOG(ERROR) << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
-    return false;
-  }
-  *hidl_ind = {};
-
-  hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
-  hidl_ind->peerDiscMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
-  hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
-  hidl_ind->securityRequired =
-        legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
-  hidl_ind->appInfo = std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
-        legacy_ind.app_info.ndp_app_info + legacy_ind.app_info.ndp_app_info_len);
-
-  return true;
-}
-
-bool convertLegacyNanDataPathConfirmIndToHidl(
-    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
-    NanDataPathConfirmInd* hidl_ind) {
-  if (!hidl_ind) {
-    LOG(ERROR) << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
-    return false;
-  }
-  *hidl_ind = {};
-
-  hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
-  hidl_ind->dataPathSetupSuccess = legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
-  hidl_ind->peerNdiMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
-  hidl_ind->appInfo = std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
-          legacy_ind.app_info.ndp_app_info + legacy_ind.app_info.ndp_app_info_len);
-  hidl_ind->status.status = convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
-  hidl_ind->status.description = ""; // TODO: b/34059183
-
-  return true;
-}
-
-legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(RttType type) {
-  switch (type) {
-    case RttType::ONE_SIDED:
-      return legacy_hal::RTT_TYPE_1_SIDED;
-    case RttType::TWO_SIDED:
-      return legacy_hal::RTT_TYPE_2_SIDED;
-  };
-  CHECK(false);
-}
-
-RttType convertLegacyRttTypeToHidl(legacy_hal::wifi_rtt_type type) {
-  switch (type) {
-    case legacy_hal::RTT_TYPE_1_SIDED:
-      return RttType::ONE_SIDED;
-    case legacy_hal::RTT_TYPE_2_SIDED:
-      return RttType::TWO_SIDED;
-  };
-  CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::rtt_peer_type convertHidlRttPeerTypeToLegacy(RttPeerType type) {
-  switch (type) {
-    case RttPeerType::AP:
-      return legacy_hal::RTT_PEER_AP;
-    case RttPeerType::STA:
-      return legacy_hal::RTT_PEER_STA;
-    case RttPeerType::P2P_GO:
-      return legacy_hal::RTT_PEER_P2P_GO;
-    case RttPeerType::P2P_CLIENT:
-      return legacy_hal::RTT_PEER_P2P_CLIENT;
-    case RttPeerType::NAN:
-      return legacy_hal::RTT_PEER_NAN;
-  };
-  CHECK(false);
-}
-
-legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(
-    WifiChannelWidthInMhz type) {
-  switch (type) {
-    case WifiChannelWidthInMhz::WIDTH_20:
-      return legacy_hal::WIFI_CHAN_WIDTH_20;
-    case WifiChannelWidthInMhz::WIDTH_40:
-      return legacy_hal::WIFI_CHAN_WIDTH_40;
-    case WifiChannelWidthInMhz::WIDTH_80:
-      return legacy_hal::WIFI_CHAN_WIDTH_80;
-    case WifiChannelWidthInMhz::WIDTH_160:
-      return legacy_hal::WIFI_CHAN_WIDTH_160;
-    case WifiChannelWidthInMhz::WIDTH_80P80:
-      return legacy_hal::WIFI_CHAN_WIDTH_80P80;
-    case WifiChannelWidthInMhz::WIDTH_5:
-      return legacy_hal::WIFI_CHAN_WIDTH_5;
-    case WifiChannelWidthInMhz::WIDTH_10:
-      return legacy_hal::WIFI_CHAN_WIDTH_10;
-    case WifiChannelWidthInMhz::WIDTH_INVALID:
-      return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
-  };
-  CHECK(false);
-}
-
-WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
-    legacy_hal::wifi_channel_width type) {
-  switch (type) {
-    case legacy_hal::WIFI_CHAN_WIDTH_20:
-      return WifiChannelWidthInMhz::WIDTH_20;
-    case legacy_hal::WIFI_CHAN_WIDTH_40:
-      return WifiChannelWidthInMhz::WIDTH_40;
-    case legacy_hal::WIFI_CHAN_WIDTH_80:
-      return WifiChannelWidthInMhz::WIDTH_80;
-    case legacy_hal::WIFI_CHAN_WIDTH_160:
-      return WifiChannelWidthInMhz::WIDTH_160;
-    case legacy_hal::WIFI_CHAN_WIDTH_80P80:
-      return WifiChannelWidthInMhz::WIDTH_80P80;
-    case legacy_hal::WIFI_CHAN_WIDTH_5:
-      return WifiChannelWidthInMhz::WIDTH_5;
-    case legacy_hal::WIFI_CHAN_WIDTH_10:
-      return WifiChannelWidthInMhz::WIDTH_10;
-    case legacy_hal::WIFI_CHAN_WIDTH_INVALID:
-      return WifiChannelWidthInMhz::WIDTH_INVALID;
-  };
-  CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(RttPreamble type) {
-  switch (type) {
-    case RttPreamble::LEGACY:
-      return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
-    case RttPreamble::HT:
-      return legacy_hal::WIFI_RTT_PREAMBLE_HT;
-    case RttPreamble::VHT:
-      return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
-  };
-  CHECK(false);
-}
-
-RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
-  switch (type) {
-    case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
-      return RttPreamble::LEGACY;
-    case legacy_hal::WIFI_RTT_PREAMBLE_HT:
-      return RttPreamble::HT;
-    case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
-      return RttPreamble::VHT;
-  };
-  CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(RttBw type) {
-  switch (type) {
-    case RttBw::BW_5MHZ:
-      return legacy_hal::WIFI_RTT_BW_5;
-    case RttBw::BW_10MHZ:
-      return legacy_hal::WIFI_RTT_BW_10;
-    case RttBw::BW_20MHZ:
-      return legacy_hal::WIFI_RTT_BW_20;
-    case RttBw::BW_40MHZ:
-      return legacy_hal::WIFI_RTT_BW_40;
-    case RttBw::BW_80MHZ:
-      return legacy_hal::WIFI_RTT_BW_80;
-    case RttBw::BW_160MHZ:
-      return legacy_hal::WIFI_RTT_BW_160;
-  };
-  CHECK(false);
-}
-
-RttBw convertLegacyRttBwToHidl(legacy_hal::wifi_rtt_bw type) {
-  switch (type) {
-    case legacy_hal::WIFI_RTT_BW_5:
-      return RttBw::BW_5MHZ;
-    case legacy_hal::WIFI_RTT_BW_10:
-      return RttBw::BW_10MHZ;
-    case legacy_hal::WIFI_RTT_BW_20:
-      return RttBw::BW_20MHZ;
-    case legacy_hal::WIFI_RTT_BW_40:
-      return RttBw::BW_40MHZ;
-    case legacy_hal::WIFI_RTT_BW_80:
-      return RttBw::BW_80MHZ;
-    case legacy_hal::WIFI_RTT_BW_160:
-      return RttBw::BW_160MHZ;
-  };
-  CHECK(false) << "Unknown legacy type: " << type;
-}
-
-legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(
-    RttMotionPattern type) {
-  switch (type) {
-    case RttMotionPattern::NOT_EXPECTED:
-      return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
-    case RttMotionPattern::EXPECTED:
-      return legacy_hal::WIFI_MOTION_EXPECTED;
-    case RttMotionPattern::UNKNOWN:
-      return legacy_hal::WIFI_MOTION_UNKNOWN;
-  };
-  CHECK(false);
-}
-
-WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
-  switch (preamble) {
-    case 0:
-      return WifiRatePreamble::OFDM;
-    case 1:
-      return WifiRatePreamble::CCK;
-    case 2:
-      return WifiRatePreamble::HT;
-    case 3:
-      return WifiRatePreamble::VHT;
-    default:
-      return WifiRatePreamble::RESERVED;
-  };
-  CHECK(false) << "Unknown legacy preamble: " << preamble;
-}
-
-WifiRateNss convertLegacyWifiRateNssToHidl(uint8_t nss) {
-  switch (nss) {
-    case 0:
-      return WifiRateNss::NSS_1x1;
-    case 1:
-      return WifiRateNss::NSS_2x2;
-    case 2:
-      return WifiRateNss::NSS_3x3;
-    case 3:
-      return WifiRateNss::NSS_4x4;
-  };
-  CHECK(false) << "Unknown legacy nss: " << nss;
-  return {};
-}
-
-RttStatus convertLegacyRttStatusToHidl(legacy_hal::wifi_rtt_status status) {
-  switch (status) {
-    case legacy_hal::RTT_STATUS_SUCCESS:
-      return RttStatus::SUCCESS;
-    case legacy_hal::RTT_STATUS_FAILURE:
-      return RttStatus::FAILURE;
-    case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
-      return RttStatus::FAIL_NO_RSP;
-    case legacy_hal::RTT_STATUS_FAIL_REJECTED:
-      return RttStatus::FAIL_REJECTED;
-    case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
-      return RttStatus::FAIL_NOT_SCHEDULED_YET;
-    case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
-      return RttStatus::FAIL_TM_TIMEOUT;
-    case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
-      return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
-    case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
-      return RttStatus::FAIL_NO_CAPABILITY;
-    case legacy_hal::RTT_STATUS_ABORTED:
-      return RttStatus::ABORTED;
-    case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
-      return RttStatus::FAIL_INVALID_TS;
-    case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
-      return RttStatus::FAIL_PROTOCOL;
-    case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
-      return RttStatus::FAIL_SCHEDULE;
-    case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
-      return RttStatus::FAIL_BUSY_TRY_LATER;
-    case legacy_hal::RTT_STATUS_INVALID_REQ:
-      return RttStatus::INVALID_REQ;
-    case legacy_hal::RTT_STATUS_NO_WIFI:
-      return RttStatus::NO_WIFI;
-    case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
-      return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
-  };
-  CHECK(false) << "Unknown legacy status: " << status;
-}
-
-bool convertHidlWifiChannelInfoToLegacy(
-    const WifiChannelInfo& hidl_info,
-    legacy_hal::wifi_channel_info* legacy_info) {
-  if (!legacy_info) {
-    return false;
-  }
-  *legacy_info = {};
-  legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
-  legacy_info->center_freq = hidl_info.centerFreq;
-  legacy_info->center_freq0 = hidl_info.centerFreq0;
-  legacy_info->center_freq1 = hidl_info.centerFreq1;
-  return true;
-}
-
-bool convertLegacyWifiChannelInfoToHidl(
-    const legacy_hal::wifi_channel_info& legacy_info,
-    WifiChannelInfo* hidl_info) {
-  if (!hidl_info) {
-    return false;
-  }
-  *hidl_info = {};
-  hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
-  hidl_info->centerFreq = legacy_info.center_freq;
-  hidl_info->centerFreq0 = legacy_info.center_freq0;
-  hidl_info->centerFreq1 = legacy_info.center_freq1;
-  return true;
-}
-
-bool convertHidlRttConfigToLegacy(const RttConfig& hidl_config,
-                                  legacy_hal::wifi_rtt_config* legacy_config) {
-  if (!legacy_config) {
-    return false;
-  }
-  *legacy_config = {};
-  CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
-  memcpy(legacy_config->addr, hidl_config.addr.data(), hidl_config.addr.size());
-  legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
-  legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
-  if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel,
-                                          &legacy_config->channel)) {
-    return false;
-  }
-  legacy_config->burst_period = hidl_config.burstPeriod;
-  legacy_config->num_burst = hidl_config.numBurst;
-  legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
-  legacy_config->num_retries_per_rtt_frame = hidl_config.numRetriesPerRttFrame;
-  legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
-  legacy_config->LCI_request = hidl_config.mustRequestLci;
-  legacy_config->LCR_request = hidl_config.mustRequestLcr;
-  legacy_config->burst_duration = hidl_config.burstDuration;
-  legacy_config->preamble =
-      convertHidlRttPreambleToLegacy(hidl_config.preamble);
-  legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
-  return true;
-}
-
-bool convertHidlVectorOfRttConfigToLegacy(
-    const std::vector<RttConfig>& hidl_configs,
-    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
-  if (!legacy_configs) {
-    return false;
-  }
-  *legacy_configs = {};
-  for (const auto& hidl_config : hidl_configs) {
-    legacy_hal::wifi_rtt_config legacy_config;
-    if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
-      return false;
-    }
-    legacy_configs->push_back(legacy_config);
-  }
-  return true;
-}
-
-bool convertHidlRttLciInformationToLegacy(
-    const RttLciInformation& hidl_info,
-    legacy_hal::wifi_lci_information* legacy_info) {
-  if (!legacy_info) {
-    return false;
-  }
-  *legacy_info = {};
-  legacy_info->latitude = hidl_info.latitude;
-  legacy_info->longitude = hidl_info.longitude;
-  legacy_info->altitude = hidl_info.altitude;
-  legacy_info->latitude_unc = hidl_info.latitudeUnc;
-  legacy_info->longitude_unc = hidl_info.longitudeUnc;
-  legacy_info->altitude_unc = hidl_info.altitudeUnc;
-  legacy_info->motion_pattern =
-      convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
-  legacy_info->floor = hidl_info.floor;
-  legacy_info->height_above_floor = hidl_info.heightAboveFloor;
-  legacy_info->height_unc = hidl_info.heightUnc;
-  return true;
-}
-
-bool convertHidlRttLcrInformationToLegacy(
-    const RttLcrInformation& hidl_info,
-    legacy_hal::wifi_lcr_information* legacy_info) {
-  if (!legacy_info) {
-    return false;
-  }
-  *legacy_info = {};
-  CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
-  memcpy(legacy_info->country_code,
-         hidl_info.countryCode.data(),
-         hidl_info.countryCode.size());
-  if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
-    return false;
-  }
-  legacy_info->length = hidl_info.civicInfo.size();
-  memcpy(legacy_info->civic_info,
-         hidl_info.civicInfo.c_str(),
-         hidl_info.civicInfo.size());
-  return true;
-}
-
-bool convertHidlRttResponderToLegacy(
-    const RttResponder& hidl_responder,
-    legacy_hal::wifi_rtt_responder* legacy_responder) {
-  if (!legacy_responder) {
-    return false;
-  }
-  *legacy_responder = {};
-  if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel,
-                                          &legacy_responder->channel)) {
-    return false;
-  }
-  legacy_responder->preamble =
-      convertHidlRttPreambleToLegacy(hidl_responder.preamble);
-  return true;
-}
-
-bool convertLegacyRttResponderToHidl(
-    const legacy_hal::wifi_rtt_responder& legacy_responder,
-    RttResponder* hidl_responder) {
-  if (!hidl_responder) {
-    return false;
-  }
-  *hidl_responder = {};
-  if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel,
-                                          &hidl_responder->channel)) {
-    return false;
-  }
-  hidl_responder->preamble =
-      convertLegacyRttPreambleToHidl(legacy_responder.preamble);
-  return true;
-}
-
-bool convertLegacyRttCapabilitiesToHidl(
-    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
-    RttCapabilities* hidl_capabilities) {
-  if (!hidl_capabilities) {
-    return false;
-  }
-  *hidl_capabilities = {};
-  hidl_capabilities->rttOneSidedSupported =
-      legacy_capabilities.rtt_one_sided_supported;
-  hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
-  hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
-  hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
-  hidl_capabilities->responderSupported =
-      legacy_capabilities.responder_supported;
-  hidl_capabilities->preambleSupport = 0;
-  for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY,
-                          legacy_hal::WIFI_RTT_PREAMBLE_HT,
-                          legacy_hal::WIFI_RTT_PREAMBLE_VHT}) {
-    if (legacy_capabilities.preamble_support & flag) {
-      hidl_capabilities->preambleSupport |=
-          static_cast<std::underlying_type<RttPreamble>::type>(
-              convertLegacyRttPreambleToHidl(flag));
-    }
-  }
-  hidl_capabilities->bwSupport = 0;
-  for (const auto flag : {legacy_hal::WIFI_RTT_BW_5,
-                          legacy_hal::WIFI_RTT_BW_10,
-                          legacy_hal::WIFI_RTT_BW_20,
-                          legacy_hal::WIFI_RTT_BW_40,
-                          legacy_hal::WIFI_RTT_BW_80,
-                          legacy_hal::WIFI_RTT_BW_160}) {
-    if (legacy_capabilities.bw_support & flag) {
-      hidl_capabilities->bwSupport |=
-          static_cast<std::underlying_type<RttBw>::type>(
-              convertLegacyRttBwToHidl(flag));
-    }
-  }
-  hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
-  return true;
-}
-
-bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
-                                     WifiRateInfo* hidl_rate) {
-  if (!hidl_rate) {
-    return false;
-  }
-  *hidl_rate = {};
-  hidl_rate->preamble =
-      convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
-  hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
-  hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
-      static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
-  hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
-  hidl_rate->bitRateInKbps = legacy_rate.bitrate;
-  return true;
-}
-
-bool convertLegacyRttResultToHidl(
-    const legacy_hal::wifi_rtt_result& legacy_result, RttResult* hidl_result) {
-  if (!hidl_result) {
-    return false;
-  }
-  *hidl_result = {};
-  CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
-  memcpy(
-      hidl_result->addr.data(), legacy_result.addr, sizeof(legacy_result.addr));
-  hidl_result->burstNum = legacy_result.burst_num;
-  hidl_result->measurementNumber = legacy_result.measurement_number;
-  hidl_result->successNumber = legacy_result.success_number;
-  hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
-  hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
-  hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
-  hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
-  hidl_result->rssi = legacy_result.rssi;
-  hidl_result->rssiSpread = legacy_result.rssi_spread;
-  if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate,
-                                       &hidl_result->txRate)) {
-    return false;
-  }
-  if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate,
-                                       &hidl_result->rxRate)) {
-    return false;
-  }
-  hidl_result->rtt = legacy_result.rtt;
-  hidl_result->rttSd = legacy_result.rtt_sd;
-  hidl_result->rttSpread = legacy_result.rtt_spread;
-  hidl_result->distanceInMm = legacy_result.distance_mm;
-  hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
-  hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
-  hidl_result->timeStampInUs = legacy_result.ts;
-  hidl_result->burstDurationInMs = legacy_result.burst_duration;
-  hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
-  if (legacy_result.LCI && !convertLegacyIeToHidl(*legacy_result.LCI,
-                                                  &hidl_result->lci)) {
-    return false;
-  }
-  if (legacy_result.LCR && !convertLegacyIeToHidl(*legacy_result.LCR,
-                                                  &hidl_result->lcr)) {
-    return false;
-  }
-  return true;
-}
-
-bool convertLegacyVectorOfRttResultToHidl(
-    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
-    std::vector<RttResult>* hidl_results) {
-  if (!hidl_results) {
-    return false;
-  }
-  *hidl_results = {};
-  for (const auto legacy_result : legacy_results) {
-    RttResult hidl_result;
-    if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
-      return false;
-    }
-    hidl_results->push_back(hidl_result);
-  }
-  return true;
-}
-}  // namespace hidl_struct_util
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/hidl_struct_util.h b/wifi/1.1/default/hidl_struct_util.h
deleted file mode 100644
index 747fd2f..0000000
--- a/wifi/1.1/default/hidl_struct_util.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * 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 HIDL_STRUCT_UTIL_H_
-#define HIDL_STRUCT_UTIL_H_
-
-#include <vector>
-
-#include <android/hardware/wifi/1.0/types.h>
-#include <android/hardware/wifi/1.0/IWifiChip.h>
-#include <android/hardware/wifi/1.1/IWifiChip.h>
-
-#include "wifi_legacy_hal.h"
-
-/**
- * This file contains a bunch of functions to convert structs from the legacy
- * HAL to HIDL and vice versa.
- * TODO(b/32093047): Add unit tests for these conversion methods in the VTS test
- * suite.
- */
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace hidl_struct_util {
-using namespace android::hardware::wifi::V1_0;
-
-// Chip conversion methods.
-bool convertLegacyFeaturesToHidlChipCapabilities(
-    uint32_t legacy_feature_set,
-    uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps);
-bool convertLegacyDebugRingBufferStatusToHidl(
-    const legacy_hal::wifi_ring_buffer_status& legacy_status,
-    WifiDebugRingBufferStatus* hidl_status);
-bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
-    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
-    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
-bool convertLegacyWakeReasonStatsToHidl(
-    const legacy_hal::WakeReasonStats& legacy_stats,
-    WifiDebugHostWakeReasonStats* hidl_stats);
-legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
-    V1_1::IWifiChip::TxPowerScenario hidl_scenario);
-
-// STA iface conversion methods.
-bool convertLegacyFeaturesToHidlStaCapabilities(
-    uint32_t legacy_feature_set,
-    uint32_t legacy_logger_feature_set,
-    uint32_t* hidl_caps);
-bool convertLegacyApfCapabilitiesToHidl(
-    const legacy_hal::PacketFilterCapabilities& legacy_caps,
-    StaApfPacketFilterCapabilities* hidl_caps);
-bool convertLegacyGscanCapabilitiesToHidl(
-    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
-    StaBackgroundScanCapabilities* hidl_caps);
-legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band);
-bool convertHidlGscanParamsToLegacy(
-    const StaBackgroundScanParameters& hidl_scan_params,
-    legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
-// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
-// Information Elements (IEs)
-bool convertLegacyGscanResultToHidl(
-    const legacy_hal::wifi_scan_result& legacy_scan_result,
-    bool has_ie_data,
-    StaScanResult* hidl_scan_result);
-// |cached_results| is assumed to not include IEs.
-bool convertLegacyVectorOfCachedGscanResultsToHidl(
-    const std::vector<legacy_hal::wifi_cached_scan_results>&
-        legacy_cached_scan_results,
-    std::vector<StaScanData>* hidl_scan_datas);
-bool convertLegacyLinkLayerStatsToHidl(
-    const legacy_hal::LinkLayerStats& legacy_stats,
-    StaLinkLayerStats* hidl_stats);
-bool convertLegacyRoamingCapabilitiesToHidl(
-    const legacy_hal::wifi_roaming_capabilities& legacy_caps,
-    StaRoamingCapabilities* hidl_caps);
-bool convertHidlRoamingConfigToLegacy(
-    const StaRoamingConfig& hidl_config,
-    legacy_hal::wifi_roaming_config* legacy_config);
-legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
-    StaRoamingState state);
-bool convertLegacyVectorOfDebugTxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
-    std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
-bool convertLegacyVectorOfDebugRxPacketFateToHidl(
-    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
-    std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
-
-// NAN iface conversion methods.
-void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str, size_t max_len,
-    WifiNanStatus* wifiNanStatus);
-bool convertHidlNanEnableRequestToLegacy(
-    const NanEnableRequest& hidl_request,
-    legacy_hal::NanEnableRequest* legacy_request);
-bool convertHidlNanConfigRequestToLegacy(
-    const NanConfigRequest& hidl_request,
-    legacy_hal::NanConfigRequest* legacy_request);
-bool convertHidlNanPublishRequestToLegacy(
-    const NanPublishRequest& hidl_request,
-    legacy_hal::NanPublishRequest* legacy_request);
-bool convertHidlNanSubscribeRequestToLegacy(
-    const NanSubscribeRequest& hidl_request,
-    legacy_hal::NanSubscribeRequest* legacy_request);
-bool convertHidlNanTransmitFollowupRequestToLegacy(
-    const NanTransmitFollowupRequest& hidl_request,
-    legacy_hal::NanTransmitFollowupRequest* legacy_request);
-bool convertHidlNanDataPathInitiatorRequestToLegacy(
-    const NanInitiateDataPathRequest& hidl_request,
-    legacy_hal::NanDataPathInitiatorRequest* legacy_request);
-bool convertHidlNanDataPathIndicationResponseToLegacy(
-    const NanRespondToDataPathIndicationRequest& hidl_response,
-    legacy_hal::NanDataPathIndicationResponse* legacy_response);
-bool convertLegacyNanResponseHeaderToHidl(
-    const legacy_hal::NanResponseMsg& legacy_response,
-    WifiNanStatus* wifiNanStatus);
-bool convertLegacyNanCapabilitiesResponseToHidl(
-    const legacy_hal::NanCapabilities& legacy_response,
-    NanCapabilities* hidl_response);
-bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
-                                    NanMatchInd* hidl_ind);
-bool convertLegacyNanFollowupIndToHidl(
-    const legacy_hal::NanFollowupInd& legacy_ind, NanFollowupReceivedInd* hidl_ind);
-bool convertLegacyNanDataPathRequestIndToHidl(
-    const legacy_hal::NanDataPathRequestInd& legacy_ind,
-    NanDataPathRequestInd* hidl_ind);
-bool convertLegacyNanDataPathConfirmIndToHidl(
-    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
-    NanDataPathConfirmInd* hidl_ind);
-
-// RTT controller conversion methods.
-bool convertHidlVectorOfRttConfigToLegacy(
-    const std::vector<RttConfig>& hidl_configs,
-    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
-bool convertHidlRttLciInformationToLegacy(
-    const RttLciInformation& hidl_info,
-    legacy_hal::wifi_lci_information* legacy_info);
-bool convertHidlRttLcrInformationToLegacy(
-    const RttLcrInformation& hidl_info,
-    legacy_hal::wifi_lcr_information* legacy_info);
-bool convertHidlRttResponderToLegacy(
-    const RttResponder& hidl_responder,
-    legacy_hal::wifi_rtt_responder* legacy_responder);
-bool convertHidlWifiChannelInfoToLegacy(
-    const WifiChannelInfo& hidl_info,
-    legacy_hal::wifi_channel_info* legacy_info);
-bool convertLegacyRttResponderToHidl(
-    const legacy_hal::wifi_rtt_responder& legacy_responder,
-    RttResponder* hidl_responder);
-bool convertLegacyRttCapabilitiesToHidl(
-    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
-    RttCapabilities* hidl_capabilities);
-bool convertLegacyVectorOfRttResultToHidl(
-    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
-    std::vector<RttResult>* hidl_results);
-}  // namespace hidl_struct_util
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // HIDL_STRUCT_UTIL_H_
diff --git a/wifi/1.1/default/hidl_sync_util.cpp b/wifi/1.1/default/hidl_sync_util.cpp
deleted file mode 100644
index ba18e34..0000000
--- a/wifi/1.1/default/hidl_sync_util.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-#include "hidl_sync_util.h"
-
-namespace {
-std::recursive_mutex g_mutex;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace hidl_sync_util {
-
-std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
-  return std::unique_lock<std::recursive_mutex>{g_mutex};
-}
-
-}  // namespace hidl_sync_util
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/hidl_sync_util.h b/wifi/1.1/default/hidl_sync_util.h
deleted file mode 100644
index 0e882df..0000000
--- a/wifi/1.1/default/hidl_sync_util.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 HIDL_SYNC_UTIL_H_
-#define HIDL_SYNC_UTIL_H_
-
-#include <mutex>
-
-// Utility that provides a global lock to synchronize access between
-// the HIDL thread and the legacy HAL's event loop.
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace hidl_sync_util {
-std::unique_lock<std::recursive_mutex> acquireGlobalLock();
-}  // namespace hidl_sync_util
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-#endif  // HIDL_SYNC_UTIL_H_
diff --git a/wifi/1.1/default/service.cpp b/wifi/1.1/default/service.cpp
deleted file mode 100644
index b4aed6c..0000000
--- a/wifi/1.1/default/service.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-#include <hidl/HidlTransportSupport.h>
-#include <utils/Looper.h>
-#include <utils/StrongPointer.h>
-
-#include "wifi.h"
-
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-
-int main(int /*argc*/, char** argv) {
-  android::base::InitLogging(argv,
-                             android::base::LogdLogger(android::base::SYSTEM));
-  LOG(INFO) << "Wifi Hal is booting up...";
-
-  configureRpcThreadpool(1, true /* callerWillJoin */);
-
-  // Setup hwbinder service
-  android::sp<android::hardware::wifi::V1_1::IWifi> service =
-      new android::hardware::wifi::V1_1::implementation::Wifi();
-  CHECK_EQ(service->registerAsService(), android::NO_ERROR)
-      << "Failed to register wifi HAL";
-
-  joinRpcThreadpool();
-
-  LOG(INFO) << "Wifi Hal is terminating...";
-  return 0;
-}
diff --git a/wifi/1.1/default/wifi.cpp b/wifi/1.1/default/wifi.cpp
deleted file mode 100644
index c46ef95..0000000
--- a/wifi/1.1/default/wifi.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "wifi.h"
-#include "wifi_status_util.h"
-
-namespace {
-// Chip ID to use for the only supported chip.
-static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0;
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-using hidl_return_util::validateAndCallWithLock;
-
-Wifi::Wifi()
-    : legacy_hal_(new legacy_hal::WifiLegacyHal()),
-      mode_controller_(new mode_controller::WifiModeController()),
-      run_state_(RunState::STOPPED) {}
-
-bool Wifi::isValid() {
-  // This object is always valid.
-  return true;
-}
-
-Return<void> Wifi::registerEventCallback(
-    const sp<IWifiEventCallback>& event_callback,
-    registerEventCallback_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_UNKNOWN,
-                         &Wifi::registerEventCallbackInternal,
-                         hidl_status_cb,
-                         event_callback);
-}
-
-Return<bool> Wifi::isStarted() {
-  return run_state_ != RunState::STOPPED;
-}
-
-Return<void> Wifi::start(start_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_UNKNOWN,
-                         &Wifi::startInternal,
-                         hidl_status_cb);
-}
-
-Return<void> Wifi::stop(stop_cb hidl_status_cb) {
-  return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN,
-                                 &Wifi::stopInternal, hidl_status_cb);
-}
-
-Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_UNKNOWN,
-                         &Wifi::getChipIdsInternal,
-                         hidl_status_cb);
-}
-
-Return<void> Wifi::getChip(ChipId chip_id, getChip_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_UNKNOWN,
-                         &Wifi::getChipInternal,
-                         hidl_status_cb,
-                         chip_id);
-}
-
-WifiStatus Wifi::registerEventCallbackInternal(
-    const sp<IWifiEventCallback>& event_callback) {
-  if (!event_cb_handler_.addCallback(event_callback)) {
-    return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus Wifi::startInternal() {
-  if (run_state_ == RunState::STARTED) {
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-  } else if (run_state_ == RunState::STOPPING) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
-                            "HAL is stopping");
-  }
-  WifiStatus wifi_status = initializeLegacyHal();
-  if (wifi_status.code == WifiStatusCode::SUCCESS) {
-    // Create the chip instance once the HAL is started.
-    chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_);
-    run_state_ = RunState::STARTED;
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-      if (!callback->onStart().isOk()) {
-        LOG(ERROR) << "Failed to invoke onStart callback";
-      };
-    }
-    LOG(INFO) << "Wifi HAL started";
-  } else {
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-      if (!callback->onFailure(wifi_status).isOk()) {
-        LOG(ERROR) << "Failed to invoke onFailure callback";
-      }
-    }
-    LOG(ERROR) << "Wifi HAL start failed";
-  }
-  return wifi_status;
-}
-
-WifiStatus Wifi::stopInternal(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
-  if (run_state_ == RunState::STOPPED) {
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-  } else if (run_state_ == RunState::STOPPING) {
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
-                            "HAL is stopping");
-  }
-  // Clear the chip object and its child objects since the HAL is now
-  // stopped.
-  if (chip_.get()) {
-    chip_->invalidate();
-    chip_.clear();
-  }
-  WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
-  if (wifi_status.code == WifiStatusCode::SUCCESS) {
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-      if (!callback->onStop().isOk()) {
-        LOG(ERROR) << "Failed to invoke onStop callback";
-      };
-    }
-    LOG(INFO) << "Wifi HAL stopped";
-  } else {
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-      if (!callback->onFailure(wifi_status).isOk()) {
-        LOG(ERROR) << "Failed to invoke onFailure callback";
-      }
-    }
-    LOG(ERROR) << "Wifi HAL stop failed";
-  }
-  return wifi_status;
-}
-
-std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
-  std::vector<ChipId> chip_ids;
-  if (chip_.get()) {
-    chip_ids.emplace_back(kChipId);
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
-}
-
-std::pair<WifiStatus, sp<IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
-  if (!chip_.get()) {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_STARTED), nullptr};
-  }
-  if (chip_id != kChipId) {
-    return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
-}
-
-WifiStatus Wifi::initializeLegacyHal() {
-  legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to initialize legacy HAL: "
-               << legacyErrorToString(legacy_status);
-    return createWifiStatusFromLegacyError(legacy_status);
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
-  run_state_ = RunState::STOPPING;
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; });
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to stop legacy HAL: "
-               << legacyErrorToString(legacy_status);
-    return createWifiStatusFromLegacyError(legacy_status);
-  }
-  if (!mode_controller_->deinitialize()) {
-    LOG(ERROR) << "Failed to deinitialize firmware mode controller";
-    return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi.h b/wifi/1.1/default/wifi.h
deleted file mode 100644
index 3a64cbd..0000000
--- a/wifi/1.1/default/wifi.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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 WIFI_H_
-#define WIFI_H_
-
-#include <functional>
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.1/IWifi.h>
-#include <utils/Looper.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_chip.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_mode_controller.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * Root HIDL interface object used to control the Wifi HAL.
- */
-class Wifi : public V1_1::IWifi {
- public:
-  Wifi();
-
-  bool isValid();
-
-  // HIDL methods exposed.
-  Return<void> registerEventCallback(
-      const sp<IWifiEventCallback>& event_callback,
-      registerEventCallback_cb hidl_status_cb) override;
-  Return<bool> isStarted() override;
-  Return<void> start(start_cb hidl_status_cb) override;
-  Return<void> stop(stop_cb hidl_status_cb) override;
-  Return<void> getChipIds(getChipIds_cb hidl_status_cb) override;
-  Return<void> getChip(ChipId chip_id, getChip_cb hidl_status_cb) override;
-
- private:
-  enum class RunState { STOPPED, STARTED, STOPPING };
-
-  // Corresponding worker functions for the HIDL methods.
-  WifiStatus registerEventCallbackInternal(
-      const sp<IWifiEventCallback>& event_callback);
-  WifiStatus startInternal();
-  WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
-  std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
-  std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
-
-  WifiStatus initializeLegacyHal();
-  WifiStatus stopLegacyHalAndDeinitializeModeController(
-      std::unique_lock<std::recursive_mutex>* lock);
-
-  // Instance is created in this root level |IWifi| HIDL interface object
-  // and shared with all the child HIDL interface objects.
-  std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-  std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
-  RunState run_state_;
-  sp<WifiChip> chip_;
-  hidl_callback_util::HidlCallbackHandler<IWifiEventCallback> event_cb_handler_;
-
-  DISALLOW_COPY_AND_ASSIGN(Wifi);
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_H_
diff --git a/wifi/1.1/default/wifi_ap_iface.cpp b/wifi/1.1/default/wifi_ap_iface.cpp
deleted file mode 100644
index 150a6cc..0000000
--- a/wifi/1.1/default/wifi_ap_iface.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_ap_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiApIface::WifiApIface(
-    const std::string& ifname,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
-
-void WifiApIface::invalidate() {
-  legacy_hal_.reset();
-  is_valid_ = false;
-}
-
-bool WifiApIface::isValid() {
-  return is_valid_;
-}
-
-Return<void> WifiApIface::getName(getName_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiApIface::getNameInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiApIface::getType(getType_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiApIface::getTypeInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiApIface::setCountryCode(const hidl_array<int8_t, 2>& code,
-                                         setCountryCode_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiApIface::setCountryCodeInternal,
-                         hidl_status_cb,
-                         code);
-}
-
-Return<void> WifiApIface::getValidFrequenciesForBand(
-    WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiApIface::getValidFrequenciesForBandInternal,
-                         hidl_status_cb,
-                         band);
-}
-
-std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
-  return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiApIface::getTypeInternal() {
-  return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::AP};
-}
-
-WifiStatus WifiApIface::setCountryCodeInternal(
-    const std::array<int8_t, 2>& code) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->setCountryCode(code);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiApIface::getValidFrequenciesForBandInternal(WifiBand band) {
-  static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t), "Size mismatch");
-  legacy_hal::wifi_error legacy_status;
-  std::vector<uint32_t> valid_frequencies;
-  std::tie(legacy_status, valid_frequencies) =
-      legacy_hal_.lock()->getValidFrequenciesForBand(
-          hidl_struct_util::convertHidlWifiBandToLegacy(band));
-  return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
-}
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi_ap_iface.h b/wifi/1.1/default/wifi_ap_iface.h
deleted file mode 100644
index 608fe6b..0000000
--- a/wifi/1.1/default/wifi_ap_iface.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 WIFI_AP_IFACE_H_
-#define WIFI_AP_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiApIface.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a AP Iface instance.
- */
-class WifiApIface : public V1_0::IWifiApIface {
- public:
-  WifiApIface(const std::string& ifname,
-              const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-  // Refer to |WifiChip::invalidate()|.
-  void invalidate();
-  bool isValid();
-
-  // HIDL methods exposed.
-  Return<void> getName(getName_cb hidl_status_cb) override;
-  Return<void> getType(getType_cb hidl_status_cb) override;
-  Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
-                              setCountryCode_cb hidl_status_cb) override;
-  Return<void> getValidFrequenciesForBand(
-      WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override;
-
- private:
-  // Corresponding worker functions for the HIDL methods.
-  std::pair<WifiStatus, std::string> getNameInternal();
-  std::pair<WifiStatus, IfaceType> getTypeInternal();
-  WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
-  std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-  getValidFrequenciesForBandInternal(WifiBand band);
-
-  std::string ifname_;
-  std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-  bool is_valid_;
-
-  DISALLOW_COPY_AND_ASSIGN(WifiApIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_AP_IFACE_H_
diff --git a/wifi/1.1/default/wifi_chip.cpp b/wifi/1.1/default/wifi_chip.cpp
deleted file mode 100644
index 2f40234..0000000
--- a/wifi/1.1/default/wifi_chip.cpp
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_chip.h"
-#include "wifi_feature_flags.h"
-#include "wifi_status_util.h"
-
-namespace {
-using android::sp;
-using android::hardware::hidl_vec;
-using android::hardware::hidl_string;
-using android::hardware::wifi::V1_0::ChipModeId;
-using android::hardware::wifi::V1_0::IWifiChip;
-using android::hardware::wifi::V1_0::IfaceType;
-
-constexpr ChipModeId kStaChipModeId = 0;
-constexpr ChipModeId kApChipModeId = 1;
-constexpr ChipModeId kInvalidModeId = UINT32_MAX;
-
-template <typename Iface>
-void invalidateAndClear(sp<Iface>& iface) {
-  if (iface.get()) {
-    iface->invalidate();
-    iface.clear();
-  }
-}
-}  // namepsace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiChip::WifiChip(
-    ChipId chip_id,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-    const std::weak_ptr<mode_controller::WifiModeController> mode_controller)
-    : chip_id_(chip_id),
-      legacy_hal_(legacy_hal),
-      mode_controller_(mode_controller),
-      is_valid_(true),
-      current_mode_id_(kInvalidModeId),
-      debug_ring_buffer_cb_registered_(false) {}
-
-void WifiChip::invalidate() {
-  invalidateAndRemoveAllIfaces();
-  legacy_hal_.reset();
-  event_cb_handler_.invalidate();
-  is_valid_ = false;
-}
-
-bool WifiChip::isValid() {
-  return is_valid_;
-}
-
-std::set<sp<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
-  return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getIdInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::registerEventCallback(
-    const sp<IWifiChipEventCallback>& event_callback,
-    registerEventCallback_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::registerEventCallbackInternal,
-                         hidl_status_cb,
-                         event_callback);
-}
-
-Return<void> WifiChip::getCapabilities(getCapabilities_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getCapabilitiesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::getAvailableModes(getAvailableModes_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getAvailableModesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::configureChip(ChipModeId mode_id,
-                                     configureChip_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::configureChipInternal,
-                         hidl_status_cb,
-                         mode_id);
-}
-
-Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getModeInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::requestChipDebugInfo(
-    requestChipDebugInfo_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::requestChipDebugInfoInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::requestDriverDebugDump(
-    requestDriverDebugDump_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::requestDriverDebugDumpInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::requestFirmwareDebugDump(
-    requestFirmwareDebugDump_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::requestFirmwareDebugDumpInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::createApIface(createApIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::createApIfaceInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getApIfaceNamesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::getApIface(const hidl_string& ifname,
-                                  getApIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getApIfaceInternal,
-                         hidl_status_cb,
-                         ifname);
-}
-
-Return<void> WifiChip::removeApIface(const hidl_string& ifname,
-                                     removeApIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::removeApIfaceInternal,
-                         hidl_status_cb,
-                         ifname);
-}
-
-Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::createNanIfaceInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getNanIfaceNamesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::getNanIface(const hidl_string& ifname,
-                                   getNanIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getNanIfaceInternal,
-                         hidl_status_cb,
-                         ifname);
-}
-
-Return<void> WifiChip::removeNanIface(const hidl_string& ifname,
-                                      removeNanIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::removeNanIfaceInternal,
-                         hidl_status_cb,
-                         ifname);
-}
-
-Return<void> WifiChip::createP2pIface(createP2pIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::createP2pIfaceInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getP2pIfaceNamesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::getP2pIface(const hidl_string& ifname,
-                                   getP2pIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getP2pIfaceInternal,
-                         hidl_status_cb,
-                         ifname);
-}
-
-Return<void> WifiChip::removeP2pIface(const hidl_string& ifname,
-                                      removeP2pIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::removeP2pIfaceInternal,
-                         hidl_status_cb,
-                         ifname);
-}
-
-Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::createStaIfaceInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getStaIfaceNamesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::getStaIface(const hidl_string& ifname,
-                                   getStaIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getStaIfaceInternal,
-                         hidl_status_cb,
-                         ifname);
-}
-
-Return<void> WifiChip::removeStaIface(const hidl_string& ifname,
-                                      removeStaIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::removeStaIfaceInternal,
-                         hidl_status_cb,
-                         ifname);
-}
-
-Return<void> WifiChip::createRttController(
-    const sp<IWifiIface>& bound_iface, createRttController_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::createRttControllerInternal,
-                         hidl_status_cb,
-                         bound_iface);
-}
-
-Return<void> WifiChip::getDebugRingBuffersStatus(
-    getDebugRingBuffersStatus_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getDebugRingBuffersStatusInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::startLoggingToDebugRingBuffer(
-    const hidl_string& ring_name,
-    WifiDebugRingBufferVerboseLevel verbose_level,
-    uint32_t max_interval_in_sec,
-    uint32_t min_data_size_in_bytes,
-    startLoggingToDebugRingBuffer_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::startLoggingToDebugRingBufferInternal,
-                         hidl_status_cb,
-                         ring_name,
-                         verbose_level,
-                         max_interval_in_sec,
-                         min_data_size_in_bytes);
-}
-
-Return<void> WifiChip::forceDumpToDebugRingBuffer(
-    const hidl_string& ring_name,
-    forceDumpToDebugRingBuffer_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::forceDumpToDebugRingBufferInternal,
-                         hidl_status_cb,
-                         ring_name);
-}
-
-Return<void> WifiChip::stopLoggingToDebugRingBuffer(
-    stopLoggingToDebugRingBuffer_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::stopLoggingToDebugRingBufferInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::getDebugHostWakeReasonStats(
-    getDebugHostWakeReasonStats_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::getDebugHostWakeReasonStatsInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiChip::enableDebugErrorAlerts(
-    bool enable, enableDebugErrorAlerts_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::enableDebugErrorAlertsInternal,
-                         hidl_status_cb,
-                         enable);
-}
-
-Return<void> WifiChip::selectTxPowerScenario(
-    TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::selectTxPowerScenarioInternal,
-                         hidl_status_cb,
-                         scenario);
-}
-
-Return<void> WifiChip::resetTxPowerScenario(
-    resetTxPowerScenario_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-                         &WifiChip::resetTxPowerScenarioInternal,
-                         hidl_status_cb);
-}
-
-void WifiChip::invalidateAndRemoveAllIfaces() {
-  invalidateAndClear(ap_iface_);
-  invalidateAndClear(nan_iface_);
-  invalidateAndClear(p2p_iface_);
-  invalidateAndClear(sta_iface_);
-  // Since all the ifaces are invalid now, all RTT controller objects
-  // using those ifaces also need to be invalidated.
-  for (const auto& rtt : rtt_controllers_) {
-    rtt->invalidate();
-  }
-  rtt_controllers_.clear();
-}
-
-std::pair<WifiStatus, ChipId> WifiChip::getIdInternal() {
-  return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_};
-}
-
-WifiStatus WifiChip::registerEventCallbackInternal(
-    const sp<IWifiChipEventCallback>& event_callback) {
-  if (!event_cb_handler_.addCallback(event_callback)) {
-    return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
-  legacy_hal::wifi_error legacy_status;
-  uint32_t legacy_feature_set;
-  uint32_t legacy_logger_feature_set;
-  std::tie(legacy_status, legacy_feature_set) =
-      legacy_hal_.lock()->getSupportedFeatureSet();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), 0};
-  }
-  std::tie(legacy_status, legacy_logger_feature_set) =
-      legacy_hal_.lock()->getLoggerSupportedFeatureSet();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), 0};
-  }
-  uint32_t hidl_caps;
-  if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
-          legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
-WifiChip::getAvailableModesInternal() {
-  // The chip combination supported for current devices is fixed for now with
-  // 2 separate modes of operation:
-  // Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN iface operations
-  // concurrently [NAN conditional on wifiHidlFeatureAware]
-  // Mode 2 (AP mode): Will support 1 AP iface operations.
-  // TODO (b/32997844): Read this from some device specific flags in the
-  // makefile.
-  // STA mode iface combinations.
-  const IWifiChip::ChipIfaceCombinationLimit
-      sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1};
-  IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_2;
-  if (WifiFeatureFlags::wifiHidlFeatureAware) {
-    sta_chip_iface_combination_limit_2 = {{IfaceType::P2P, IfaceType::NAN},
-                                          1};
-  } else {
-    sta_chip_iface_combination_limit_2 = {{IfaceType::P2P},
-                                          1};
-  }
-  const IWifiChip::ChipIfaceCombination sta_chip_iface_combination = {
-      {sta_chip_iface_combination_limit_1, sta_chip_iface_combination_limit_2}};
-  const IWifiChip::ChipMode sta_chip_mode = {kStaChipModeId,
-                                             {sta_chip_iface_combination}};
-  // AP mode iface combinations.
-  const IWifiChip::ChipIfaceCombinationLimit ap_chip_iface_combination_limit = {
-      {IfaceType::AP}, 1};
-  const IWifiChip::ChipIfaceCombination ap_chip_iface_combination = {
-      {ap_chip_iface_combination_limit}};
-  const IWifiChip::ChipMode ap_chip_mode = {kApChipModeId,
-                                            {ap_chip_iface_combination}};
-  return {createWifiStatus(WifiStatusCode::SUCCESS),
-          {sta_chip_mode, ap_chip_mode}};
-}
-
-WifiStatus WifiChip::configureChipInternal(ChipModeId mode_id) {
-  if (mode_id != kStaChipModeId && mode_id != kApChipModeId) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  if (mode_id == current_mode_id_) {
-    LOG(DEBUG) << "Already in the specified mode " << mode_id;
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-  }
-  WifiStatus status = handleChipConfiguration(mode_id);
-  if (status.code != WifiStatusCode::SUCCESS) {
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-      if (!callback->onChipReconfigureFailure(status).isOk()) {
-        LOG(ERROR) << "Failed to invoke onChipReconfigureFailure callback";
-      }
-    }
-    return status;
-  }
-  for (const auto& callback : event_cb_handler_.getCallbacks()) {
-    if (!callback->onChipReconfigured(mode_id).isOk()) {
-      LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
-    }
-  }
-  current_mode_id_ = mode_id;
-  return status;
-}
-
-std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
-  if (current_mode_id_ == kInvalidModeId) {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
-            current_mode_id_};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
-}
-
-std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
-WifiChip::requestChipDebugInfoInternal() {
-  IWifiChip::ChipDebugInfo result;
-  legacy_hal::wifi_error legacy_status;
-  std::string driver_desc;
-  std::tie(legacy_status, driver_desc) = legacy_hal_.lock()->getDriverVersion();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to get driver version: "
-               << legacyErrorToString(legacy_status);
-    WifiStatus status = createWifiStatusFromLegacyError(
-        legacy_status, "failed to get driver version");
-    return {status, result};
-  }
-  result.driverDescription = driver_desc.c_str();
-
-  std::string firmware_desc;
-  std::tie(legacy_status, firmware_desc) =
-      legacy_hal_.lock()->getFirmwareVersion();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to get firmware version: "
-               << legacyErrorToString(legacy_status);
-    WifiStatus status = createWifiStatusFromLegacyError(
-        legacy_status, "failed to get firmware version");
-    return {status, result};
-  }
-  result.firmwareDescription = firmware_desc.c_str();
-
-  return {createWifiStatus(WifiStatusCode::SUCCESS), result};
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiChip::requestDriverDebugDumpInternal() {
-  legacy_hal::wifi_error legacy_status;
-  std::vector<uint8_t> driver_dump;
-  std::tie(legacy_status, driver_dump) =
-      legacy_hal_.lock()->requestDriverMemoryDump();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to get driver debug dump: "
-               << legacyErrorToString(legacy_status);
-    return {createWifiStatusFromLegacyError(legacy_status),
-            std::vector<uint8_t>()};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), driver_dump};
-}
-
-std::pair<WifiStatus, std::vector<uint8_t>>
-WifiChip::requestFirmwareDebugDumpInternal() {
-  legacy_hal::wifi_error legacy_status;
-  std::vector<uint8_t> firmware_dump;
-  std::tie(legacy_status, firmware_dump) =
-      legacy_hal_.lock()->requestFirmwareMemoryDump();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to get firmware debug dump: "
-               << legacyErrorToString(legacy_status);
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
-}
-
-std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
-  if (current_mode_id_ != kApChipModeId || ap_iface_.get()) {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-  }
-  std::string ifname = legacy_hal_.lock()->getApIfaceName();
-  ap_iface_ = new WifiApIface(ifname, legacy_hal_);
-  for (const auto& callback : event_cb_handler_.getCallbacks()) {
-    if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
-      LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-    }
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), ap_iface_};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getApIfaceNamesInternal() {
-  if (!ap_iface_.get()) {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS),
-          {legacy_hal_.lock()->getApIfaceName()}};
-}
-
-std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::getApIfaceInternal(
-    const std::string& ifname) {
-  if (!ap_iface_.get() || (ifname != legacy_hal_.lock()->getApIfaceName())) {
-    return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), ap_iface_};
-}
-
-WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
-  if (!ap_iface_.get() || (ifname != legacy_hal_.lock()->getApIfaceName())) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  invalidateAndClear(ap_iface_);
-  for (const auto& callback : event_cb_handler_.getCallbacks()) {
-    if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
-      LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-    }
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
-  // Only 1 of NAN or P2P iface can be active at a time.
-  if (WifiFeatureFlags::wifiHidlFeatureAware) {
-    if (current_mode_id_ != kStaChipModeId || nan_iface_.get() ||
-        p2p_iface_.get()) {
-      return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-    }
-    std::string ifname = legacy_hal_.lock()->getNanIfaceName();
-    nan_iface_ = new WifiNanIface(ifname, legacy_hal_);
-    for (const auto& callback : event_cb_handler_.getCallbacks()) {
-      if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
-        LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-      }
-    }
-    return {createWifiStatus(WifiStatusCode::SUCCESS), nan_iface_};
-  } else {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-  }
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getNanIfaceNamesInternal() {
-  if (!nan_iface_.get()) {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS),
-          {legacy_hal_.lock()->getNanIfaceName()}};
-}
-
-std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::getNanIfaceInternal(
-    const std::string& ifname) {
-  if (!nan_iface_.get() || (ifname != legacy_hal_.lock()->getNanIfaceName())) {
-    return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), nan_iface_};
-}
-
-WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
-  if (!nan_iface_.get() || (ifname != legacy_hal_.lock()->getNanIfaceName())) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  invalidateAndClear(nan_iface_);
-  for (const auto& callback : event_cb_handler_.getCallbacks()) {
-    if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) {
-      LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-    }
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
-  // Only 1 of NAN or P2P iface can be active at a time.
-  if (current_mode_id_ != kStaChipModeId || p2p_iface_.get() ||
-      nan_iface_.get()) {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-  }
-  std::string ifname = legacy_hal_.lock()->getP2pIfaceName();
-  p2p_iface_ = new WifiP2pIface(ifname, legacy_hal_);
-  for (const auto& callback : event_cb_handler_.getCallbacks()) {
-    if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
-      LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-    }
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), p2p_iface_};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getP2pIfaceNamesInternal() {
-  if (!p2p_iface_.get()) {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS),
-          {legacy_hal_.lock()->getP2pIfaceName()}};
-}
-
-std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::getP2pIfaceInternal(
-    const std::string& ifname) {
-  if (!p2p_iface_.get() || (ifname != legacy_hal_.lock()->getP2pIfaceName())) {
-    return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), p2p_iface_};
-}
-
-WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
-  if (!p2p_iface_.get() || (ifname != legacy_hal_.lock()->getP2pIfaceName())) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  invalidateAndClear(p2p_iface_);
-  for (const auto& callback : event_cb_handler_.getCallbacks()) {
-    if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
-      LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-    }
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {
-  if (current_mode_id_ != kStaChipModeId || sta_iface_.get()) {
-    return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
-  }
-  std::string ifname = legacy_hal_.lock()->getStaIfaceName();
-  sta_iface_ = new WifiStaIface(ifname, legacy_hal_);
-  for (const auto& callback : event_cb_handler_.getCallbacks()) {
-    if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
-      LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
-    }
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), sta_iface_};
-}
-
-std::pair<WifiStatus, std::vector<hidl_string>>
-WifiChip::getStaIfaceNamesInternal() {
-  if (!sta_iface_.get()) {
-    return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS),
-          {legacy_hal_.lock()->getStaIfaceName()}};
-}
-
-std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::getStaIfaceInternal(
-    const std::string& ifname) {
-  if (!sta_iface_.get() || (ifname != legacy_hal_.lock()->getStaIfaceName())) {
-    return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), sta_iface_};
-}
-
-WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
-  if (!sta_iface_.get() || (ifname != legacy_hal_.lock()->getStaIfaceName())) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  invalidateAndClear(sta_iface_);
-  for (const auto& callback : event_cb_handler_.getCallbacks()) {
-    if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
-      LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
-    }
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, sp<IWifiRttController>>
-WifiChip::createRttControllerInternal(const sp<IWifiIface>& bound_iface) {
-  sp<WifiRttController> rtt = new WifiRttController(bound_iface, legacy_hal_);
-  rtt_controllers_.emplace_back(rtt);
-  return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
-WifiChip::getDebugRingBuffersStatusInternal() {
-  legacy_hal::wifi_error legacy_status;
-  std::vector<legacy_hal::wifi_ring_buffer_status>
-      legacy_ring_buffer_status_vec;
-  std::tie(legacy_status, legacy_ring_buffer_status_vec) =
-      legacy_hal_.lock()->getRingBuffersStatus();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
-  if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
-          legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS),
-          hidl_ring_buffer_status_vec};
-}
-
-WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
-    const hidl_string& ring_name,
-    WifiDebugRingBufferVerboseLevel verbose_level,
-    uint32_t max_interval_in_sec,
-    uint32_t min_data_size_in_bytes) {
-  WifiStatus status = registerDebugRingBufferCallback();
-  if (status.code != WifiStatusCode::SUCCESS) {
-    return status;
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->startRingBufferLogging(
-          ring_name,
-          static_cast<
-              std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(
-              verbose_level),
-          max_interval_in_sec,
-          min_data_size_in_bytes);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(
-    const hidl_string& ring_name) {
-  WifiStatus status = registerDebugRingBufferCallback();
-  if (status.code != WifiStatusCode::SUCCESS) {
-    return status;
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->getRingBufferData(ring_name);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->deregisterRingBufferCallbackHandler();
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
-WifiChip::getDebugHostWakeReasonStatsInternal() {
-  legacy_hal::wifi_error legacy_status;
-  legacy_hal::WakeReasonStats legacy_stats;
-  std::tie(legacy_status, legacy_stats) =
-      legacy_hal_.lock()->getWakeReasonStats();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  WifiDebugHostWakeReasonStats hidl_stats;
-  if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats,
-                                                            &hidl_stats)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
-}
-
-WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
-  legacy_hal::wifi_error legacy_status;
-  if (enable) {
-    android::wp<WifiChip> weak_ptr_this(this);
-    const auto& on_alert_callback = [weak_ptr_this](
-        int32_t error_code, std::vector<uint8_t> debug_data) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->onDebugErrorAlert(error_code, debug_data).isOk()) {
-          LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
-        }
-      }
-    };
-    legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
-        on_alert_callback);
-  } else {
-    legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler();
-  }
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::selectTxPowerScenarioInternal(TxPowerScenario scenario) {
-  auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
-      hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::resetTxPowerScenarioInternal() {
-  auto legacy_status = legacy_hal_.lock()->resetTxPowerScenario();
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiChip::handleChipConfiguration(ChipModeId mode_id) {
-  // If the chip is already configured in a different mode, stop
-  // the legacy HAL and then start it after firmware mode change.
-  // Currently the underlying implementation has a deadlock issue.
-  // We should return ERROR_NOT_SUPPORTED if chip is already configured in
-  // a different mode.
-  if (current_mode_id_ != kInvalidModeId) {
-    // TODO(b/37446050): Fix the deadlock.
-    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
-  }
-  bool success;
-  if (mode_id == kStaChipModeId) {
-    success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
-  } else {
-    success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
-  }
-  if (!success) {
-    return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-  }
-  legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to start legacy HAL: "
-               << legacyErrorToString(legacy_status);
-    return createWifiStatusFromLegacyError(legacy_status);
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiChip::registerDebugRingBufferCallback() {
-  if (debug_ring_buffer_cb_registered_) {
-    return createWifiStatus(WifiStatusCode::SUCCESS);
-  }
-
-  android::wp<WifiChip> weak_ptr_this(this);
-  const auto& on_ring_buffer_data_callback = [weak_ptr_this](
-      const std::string& /* name */,
-      const std::vector<uint8_t>& data,
-      const legacy_hal::wifi_ring_buffer_status& status) {
-    const auto shared_ptr_this = weak_ptr_this.promote();
-    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-      LOG(ERROR) << "Callback invoked on an invalid object";
-      return;
-    }
-    WifiDebugRingBufferStatus hidl_status;
-    if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(
-            status, &hidl_status)) {
-      LOG(ERROR) << "Error converting ring buffer status";
-      return;
-    }
-    for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-      if (!callback->onDebugRingBufferDataAvailable(hidl_status, data).isOk()) {
-        LOG(ERROR) << "Failed to invoke onDebugRingBufferDataAvailable"
-                   << " callback on: " << toString(callback);
-
-      }
-    }
-  };
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->registerRingBufferCallbackHandler(
-          on_ring_buffer_data_callback);
-
-  if (legacy_status == legacy_hal::WIFI_SUCCESS) {
-    debug_ring_buffer_cb_registered_ = true;
-  }
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi_chip.h b/wifi/1.1/default/wifi_chip.h
deleted file mode 100644
index e88100b..0000000
--- a/wifi/1.1/default/wifi_chip.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * 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 WIFI_CHIP_H_
-#define WIFI_CHIP_H_
-
-#include <map>
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.1/IWifiChip.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_ap_iface.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_mode_controller.h"
-#include "wifi_nan_iface.h"
-#include "wifi_p2p_iface.h"
-#include "wifi_rtt_controller.h"
-#include "wifi_sta_iface.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a Wifi HAL chip instance.
- * Since there is only a single chip instance used today, there is no
- * identifying handle information stored here.
- */
-class WifiChip : public V1_1::IWifiChip {
- public:
-  WifiChip(
-      ChipId chip_id,
-      const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
-      const std::weak_ptr<mode_controller::WifiModeController> mode_controller);
-  // HIDL does not provide a built-in mechanism to let the server invalidate
-  // a HIDL interface object after creation. If any client process holds onto
-  // a reference to the object in their context, any method calls on that
-  // reference will continue to be directed to the server.
-  //
-  // However Wifi HAL needs to control the lifetime of these objects. So, add
-  // a public |invalidate| method to |WifiChip| and it's child objects. This
-  // will be used to mark an object invalid when either:
-  // a) Wifi HAL is stopped, or
-  // b) Wifi Chip is reconfigured.
-  //
-  // All HIDL method implementations should check if the object is still marked
-  // valid before processing them.
-  void invalidate();
-  bool isValid();
-  std::set<sp<IWifiChipEventCallback>> getEventCallbacks();
-
-  // HIDL methods exposed.
-  Return<void> getId(getId_cb hidl_status_cb) override;
-  Return<void> registerEventCallback(
-      const sp<IWifiChipEventCallback>& event_callback,
-      registerEventCallback_cb hidl_status_cb) override;
-  Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-  Return<void> getAvailableModes(getAvailableModes_cb hidl_status_cb) override;
-  Return<void> configureChip(ChipModeId mode_id,
-                             configureChip_cb hidl_status_cb) override;
-  Return<void> getMode(getMode_cb hidl_status_cb) override;
-  Return<void> requestChipDebugInfo(
-      requestChipDebugInfo_cb hidl_status_cb) override;
-  Return<void> requestDriverDebugDump(
-      requestDriverDebugDump_cb hidl_status_cb) override;
-  Return<void> requestFirmwareDebugDump(
-      requestFirmwareDebugDump_cb hidl_status_cb) override;
-  Return<void> createApIface(createApIface_cb hidl_status_cb) override;
-  Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
-  Return<void> getApIface(const hidl_string& ifname,
-                          getApIface_cb hidl_status_cb) override;
-  Return<void> removeApIface(const hidl_string& ifname,
-                             removeApIface_cb hidl_status_cb) override;
-  Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
-  Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
-  Return<void> getNanIface(const hidl_string& ifname,
-                           getNanIface_cb hidl_status_cb) override;
-  Return<void> removeNanIface(const hidl_string& ifname,
-                              removeNanIface_cb hidl_status_cb) override;
-  Return<void> createP2pIface(createP2pIface_cb hidl_status_cb) override;
-  Return<void> getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) override;
-  Return<void> getP2pIface(const hidl_string& ifname,
-                           getP2pIface_cb hidl_status_cb) override;
-  Return<void> removeP2pIface(const hidl_string& ifname,
-                              removeP2pIface_cb hidl_status_cb) override;
-  Return<void> createStaIface(createStaIface_cb hidl_status_cb) override;
-  Return<void> getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) override;
-  Return<void> getStaIface(const hidl_string& ifname,
-                           getStaIface_cb hidl_status_cb) override;
-  Return<void> removeStaIface(const hidl_string& ifname,
-                              removeStaIface_cb hidl_status_cb) override;
-  Return<void> createRttController(
-      const sp<IWifiIface>& bound_iface,
-      createRttController_cb hidl_status_cb) override;
-  Return<void> getDebugRingBuffersStatus(
-      getDebugRingBuffersStatus_cb hidl_status_cb) override;
-  Return<void> startLoggingToDebugRingBuffer(
-      const hidl_string& ring_name,
-      WifiDebugRingBufferVerboseLevel verbose_level,
-      uint32_t max_interval_in_sec,
-      uint32_t min_data_size_in_bytes,
-      startLoggingToDebugRingBuffer_cb hidl_status_cb) override;
-  Return<void> forceDumpToDebugRingBuffer(
-      const hidl_string& ring_name,
-      forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
-  Return<void> stopLoggingToDebugRingBuffer(
-      stopLoggingToDebugRingBuffer_cb hidl_status_cb) override;
-  Return<void> getDebugHostWakeReasonStats(
-      getDebugHostWakeReasonStats_cb hidl_status_cb) override;
-  Return<void> enableDebugErrorAlerts(
-      bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
-  Return<void> selectTxPowerScenario(
-      TxPowerScenario scenario,
-      selectTxPowerScenario_cb hidl_status_cb) override;
-  Return<void> resetTxPowerScenario(
-      resetTxPowerScenario_cb hidl_status_cb) override;
-
- private:
-  void invalidateAndRemoveAllIfaces();
-
-  // Corresponding worker functions for the HIDL methods.
-  std::pair<WifiStatus, ChipId> getIdInternal();
-  WifiStatus registerEventCallbackInternal(
-      const sp<IWifiChipEventCallback>& event_callback);
-  std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
-  std::pair<WifiStatus, std::vector<ChipMode>> getAvailableModesInternal();
-  WifiStatus configureChipInternal(ChipModeId mode_id);
-  std::pair<WifiStatus, uint32_t> getModeInternal();
-  std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
-  requestChipDebugInfoInternal();
-  std::pair<WifiStatus, std::vector<uint8_t>> requestDriverDebugDumpInternal();
-  std::pair<WifiStatus, std::vector<uint8_t>>
-  requestFirmwareDebugDumpInternal();
-  std::pair<WifiStatus, sp<IWifiApIface>> createApIfaceInternal();
-  std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
-  std::pair<WifiStatus, sp<IWifiApIface>> getApIfaceInternal(
-      const std::string& ifname);
-  WifiStatus removeApIfaceInternal(const std::string& ifname);
-  std::pair<WifiStatus, sp<IWifiNanIface>> createNanIfaceInternal();
-  std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
-  std::pair<WifiStatus, sp<IWifiNanIface>> getNanIfaceInternal(
-      const std::string& ifname);
-  WifiStatus removeNanIfaceInternal(const std::string& ifname);
-  std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
-  std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
-  std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(
-      const std::string& ifname);
-  WifiStatus removeP2pIfaceInternal(const std::string& ifname);
-  std::pair<WifiStatus, sp<IWifiStaIface>> createStaIfaceInternal();
-  std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
-  std::pair<WifiStatus, sp<IWifiStaIface>> getStaIfaceInternal(
-      const std::string& ifname);
-  WifiStatus removeStaIfaceInternal(const std::string& ifname);
-  std::pair<WifiStatus, sp<IWifiRttController>> createRttControllerInternal(
-      const sp<IWifiIface>& bound_iface);
-  std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
-  getDebugRingBuffersStatusInternal();
-  WifiStatus startLoggingToDebugRingBufferInternal(
-      const hidl_string& ring_name,
-      WifiDebugRingBufferVerboseLevel verbose_level,
-      uint32_t max_interval_in_sec,
-      uint32_t min_data_size_in_bytes);
-  WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
-  WifiStatus stopLoggingToDebugRingBufferInternal();
-  std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
-  getDebugHostWakeReasonStatsInternal();
-  WifiStatus enableDebugErrorAlertsInternal(bool enable);
-  WifiStatus selectTxPowerScenarioInternal(TxPowerScenario scenario);
-  WifiStatus resetTxPowerScenarioInternal();
-
-  WifiStatus handleChipConfiguration(ChipModeId mode_id);
-  WifiStatus registerDebugRingBufferCallback();
-
-  ChipId chip_id_;
-  std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-  std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
-  sp<WifiApIface> ap_iface_;
-  sp<WifiNanIface> nan_iface_;
-  sp<WifiP2pIface> p2p_iface_;
-  sp<WifiStaIface> sta_iface_;
-  std::vector<sp<WifiRttController>> rtt_controllers_;
-  bool is_valid_;
-  uint32_t current_mode_id_;
-  // The legacy ring buffer callback API has only a global callback
-  // registration mechanism. Use this to check if we have already
-  // registered a callback.
-  bool debug_ring_buffer_cb_registered_;
-  hidl_callback_util::HidlCallbackHandler<IWifiChipEventCallback>
-      event_cb_handler_;
-
-  DISALLOW_COPY_AND_ASSIGN(WifiChip);
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_CHIP_H_
diff --git a/wifi/1.1/default/wifi_feature_flags.h b/wifi/1.1/default/wifi_feature_flags.h
deleted file mode 100644
index 5939ffb..0000000
--- a/wifi/1.1/default/wifi_feature_flags.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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 WIFI_FEATURE_FLAGS_H_
-#define WIFI_FEATURE_FLAGS_H_
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-
-class WifiFeatureFlags {
- public:
-#ifdef WIFI_HIDL_FEATURE_AWARE
-  static const bool wifiHidlFeatureAware = true;
-#else
-  static const bool wifiHidlFeatureAware = false;
-#endif // WIFI_HIDL_FEATURE_AWARE
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.1/default/wifi_legacy_hal.cpp b/wifi/1.1/default/wifi_legacy_hal.cpp
deleted file mode 100644
index 36da6e5..0000000
--- a/wifi/1.1/default/wifi_legacy_hal.cpp
+++ /dev/null
@@ -1,1345 +0,0 @@
-/*
- * 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.
- */
-
-#include <array>
-#include <chrono>
-
-#include <android-base/logging.h>
-#include <cutils/properties.h>
-
-#include "hidl_sync_util.h"
-#include "wifi_legacy_hal.h"
-#include "wifi_legacy_hal_stubs.h"
-
-namespace {
-// Constants ported over from the legacy HAL calling code
-// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
-// away when this shim layer is replaced by the real vendor
-// implementation.
-static constexpr uint32_t kMaxVersionStringLength = 256;
-static constexpr uint32_t kMaxCachedGscanResults = 64;
-static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
-static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
-static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
-static constexpr uint32_t kMaxRingBuffers = 10;
-static constexpr uint32_t kMaxStopCompleteWaitMs = 100;
-
-// Helper function to create a non-const char* for legacy Hal API's.
-std::vector<char> makeCharVec(const std::string& str) {
-  std::vector<char> vec(str.size() + 1);
-  vec.assign(str.begin(), str.end());
-  vec.push_back('\0');
-  return vec;
-}
-}  // namespace
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace legacy_hal {
-// Legacy HAL functions accept "C" style function pointers, so use global
-// functions to pass to the legacy HAL function and store the corresponding
-// std::function methods to be invoked.
-//
-// Callback to be invoked once |stop| is complete
-std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
-void onAsyncStopComplete(wifi_handle handle) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_stop_complete_internal_callback) {
-    on_stop_complete_internal_callback(handle);
-    // Invalidate this callback since we don't want this firing again.
-    on_stop_complete_internal_callback = nullptr;
-  }
-}
-
-// Callback to be invoked for driver dump.
-std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
-void onSyncDriverMemoryDump(char* buffer, int buffer_size) {
-  if (on_driver_memory_dump_internal_callback) {
-    on_driver_memory_dump_internal_callback(buffer, buffer_size);
-  }
-}
-
-// Callback to be invoked for firmware dump.
-std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
-void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) {
-  if (on_firmware_memory_dump_internal_callback) {
-    on_firmware_memory_dump_internal_callback(buffer, buffer_size);
-  }
-}
-
-// Callback to be invoked for Gscan events.
-std::function<void(wifi_request_id, wifi_scan_event)>
-    on_gscan_event_internal_callback;
-void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_gscan_event_internal_callback) {
-    on_gscan_event_internal_callback(id, event);
-  }
-}
-
-// Callback to be invoked for Gscan full results.
-std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
-    on_gscan_full_result_internal_callback;
-void onAsyncGscanFullResult(wifi_request_id id,
-                            wifi_scan_result* result,
-                            uint32_t buckets_scanned) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_gscan_full_result_internal_callback) {
-    on_gscan_full_result_internal_callback(id, result, buckets_scanned);
-  }
-}
-
-// Callback to be invoked for link layer stats results.
-std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
-    on_link_layer_stats_result_internal_callback;
-void onSyncLinkLayerStatsResult(wifi_request_id id,
-                                wifi_iface_stat* iface_stat,
-                                int num_radios,
-                                wifi_radio_stat* radio_stat) {
-  if (on_link_layer_stats_result_internal_callback) {
-    on_link_layer_stats_result_internal_callback(
-        id, iface_stat, num_radios, radio_stat);
-  }
-}
-
-// Callback to be invoked for rssi threshold breach.
-std::function<void((wifi_request_id, uint8_t*, int8_t))>
-    on_rssi_threshold_breached_internal_callback;
-void onAsyncRssiThresholdBreached(wifi_request_id id,
-                                  uint8_t* bssid,
-                                  int8_t rssi) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_rssi_threshold_breached_internal_callback) {
-    on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
-  }
-}
-
-// Callback to be invoked for ring buffer data indication.
-std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
-    on_ring_buffer_data_internal_callback;
-void onAsyncRingBufferData(char* ring_name,
-                           char* buffer,
-                           int buffer_size,
-                           wifi_ring_buffer_status* status) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_ring_buffer_data_internal_callback) {
-    on_ring_buffer_data_internal_callback(
-        ring_name, buffer, buffer_size, status);
-  }
-}
-
-// Callback to be invoked for error alert indication.
-std::function<void(wifi_request_id, char*, int, int)>
-    on_error_alert_internal_callback;
-void onAsyncErrorAlert(wifi_request_id id,
-                       char* buffer,
-                       int buffer_size,
-                       int err_code) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_error_alert_internal_callback) {
-    on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
-  }
-}
-
-// Callback to be invoked for rtt results results.
-std::function<void(
-    wifi_request_id, unsigned num_results, wifi_rtt_result* rtt_results[])>
-    on_rtt_results_internal_callback;
-void onAsyncRttResults(wifi_request_id id,
-                       unsigned num_results,
-                       wifi_rtt_result* rtt_results[]) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_rtt_results_internal_callback) {
-    on_rtt_results_internal_callback(id, num_results, rtt_results);
-    on_rtt_results_internal_callback = nullptr;
-  }
-}
-
-// Callbacks for the various NAN operations.
-// NOTE: These have very little conversions to perform before invoking the user
-// callbacks.
-// So, handle all of them here directly to avoid adding an unnecessary layer.
-std::function<void(transaction_id, const NanResponseMsg&)>
-    on_nan_notify_response_user_callback;
-void onAysncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_notify_response_user_callback && msg) {
-    on_nan_notify_response_user_callback(id, *msg);
-  }
-}
-
-std::function<void(const NanPublishRepliedInd&)>
-    on_nan_event_publish_replied_user_callback;
-void onAysncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
-  LOG(ERROR) << "onAysncNanEventPublishReplied triggered";
-}
-
-std::function<void(const NanPublishTerminatedInd&)>
-    on_nan_event_publish_terminated_user_callback;
-void onAysncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_publish_terminated_user_callback && event) {
-    on_nan_event_publish_terminated_user_callback(*event);
-  }
-}
-
-std::function<void(const NanMatchInd&)> on_nan_event_match_user_callback;
-void onAysncNanEventMatch(NanMatchInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_match_user_callback && event) {
-    on_nan_event_match_user_callback(*event);
-  }
-}
-
-std::function<void(const NanMatchExpiredInd&)>
-    on_nan_event_match_expired_user_callback;
-void onAysncNanEventMatchExpired(NanMatchExpiredInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_match_expired_user_callback && event) {
-    on_nan_event_match_expired_user_callback(*event);
-  }
-}
-
-std::function<void(const NanSubscribeTerminatedInd&)>
-    on_nan_event_subscribe_terminated_user_callback;
-void onAysncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_subscribe_terminated_user_callback && event) {
-    on_nan_event_subscribe_terminated_user_callback(*event);
-  }
-}
-
-std::function<void(const NanFollowupInd&)> on_nan_event_followup_user_callback;
-void onAysncNanEventFollowup(NanFollowupInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_followup_user_callback && event) {
-    on_nan_event_followup_user_callback(*event);
-  }
-}
-
-std::function<void(const NanDiscEngEventInd&)>
-    on_nan_event_disc_eng_event_user_callback;
-void onAysncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_disc_eng_event_user_callback && event) {
-    on_nan_event_disc_eng_event_user_callback(*event);
-  }
-}
-
-std::function<void(const NanDisabledInd&)> on_nan_event_disabled_user_callback;
-void onAysncNanEventDisabled(NanDisabledInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_disabled_user_callback && event) {
-    on_nan_event_disabled_user_callback(*event);
-  }
-}
-
-std::function<void(const NanTCAInd&)> on_nan_event_tca_user_callback;
-void onAysncNanEventTca(NanTCAInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_tca_user_callback && event) {
-    on_nan_event_tca_user_callback(*event);
-  }
-}
-
-std::function<void(const NanBeaconSdfPayloadInd&)>
-    on_nan_event_beacon_sdf_payload_user_callback;
-void onAysncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_beacon_sdf_payload_user_callback && event) {
-    on_nan_event_beacon_sdf_payload_user_callback(*event);
-  }
-}
-
-std::function<void(const NanDataPathRequestInd&)>
-    on_nan_event_data_path_request_user_callback;
-void onAysncNanEventDataPathRequest(NanDataPathRequestInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_data_path_request_user_callback && event) {
-    on_nan_event_data_path_request_user_callback(*event);
-  }
-}
-std::function<void(const NanDataPathConfirmInd&)>
-    on_nan_event_data_path_confirm_user_callback;
-void onAysncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_data_path_confirm_user_callback && event) {
-    on_nan_event_data_path_confirm_user_callback(*event);
-  }
-}
-
-std::function<void(const NanDataPathEndInd&)>
-    on_nan_event_data_path_end_user_callback;
-void onAysncNanEventDataPathEnd(NanDataPathEndInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_data_path_end_user_callback && event) {
-    on_nan_event_data_path_end_user_callback(*event);
-  }
-}
-
-std::function<void(const NanTransmitFollowupInd&)>
-    on_nan_event_transmit_follow_up_user_callback;
-void onAysncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_transmit_follow_up_user_callback && event) {
-    on_nan_event_transmit_follow_up_user_callback(*event);
-  }
-}
-
-std::function<void(const NanRangeRequestInd&)>
-    on_nan_event_range_request_user_callback;
-void onAysncNanEventRangeRequest(NanRangeRequestInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_range_request_user_callback && event) {
-    on_nan_event_range_request_user_callback(*event);
-  }
-}
-
-std::function<void(const NanRangeReportInd&)>
-    on_nan_event_range_report_user_callback;
-void onAysncNanEventRangeReport(NanRangeReportInd* event) {
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (on_nan_event_range_report_user_callback && event) {
-    on_nan_event_range_report_user_callback(*event);
-  }
-}
-// End of the free-standing "C" style callbacks.
-
-WifiLegacyHal::WifiLegacyHal()
-    : global_handle_(nullptr),
-      wlan_interface_handle_(nullptr),
-      awaiting_event_loop_termination_(false),
-      is_started_(false) {}
-
-wifi_error WifiLegacyHal::initialize() {
-  LOG(DEBUG) << "Initialize legacy HAL";
-  // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
-  // for now is this function call which we can directly call.
-  if (!initHalFuncTableWithStubs(&global_func_table_)) {
-    LOG(ERROR) << "Failed to initialize legacy hal function table with stubs";
-    return WIFI_ERROR_UNKNOWN;
-  }
-  wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
-  if (status != WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to initialize legacy hal function table";
-  }
-  return status;
-}
-
-wifi_error WifiLegacyHal::start() {
-  // Ensure that we're starting in a good state.
-  CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
-        !wlan_interface_handle_ && !awaiting_event_loop_termination_);
-  if (is_started_) {
-    LOG(DEBUG) << "Legacy HAL already started";
-    return WIFI_SUCCESS;
-  }
-  LOG(DEBUG) << "Starting legacy HAL";
-  if (!iface_tool_.SetWifiUpState(true)) {
-    LOG(ERROR) << "Failed to set WiFi interface up";
-    return WIFI_ERROR_UNKNOWN;
-  }
-  wifi_error status = global_func_table_.wifi_initialize(&global_handle_);
-  if (status != WIFI_SUCCESS || !global_handle_) {
-    LOG(ERROR) << "Failed to retrieve global handle";
-    return status;
-  }
-  std::thread(&WifiLegacyHal::runEventLoop, this).detach();
-  status = retrieveWlanInterfaceHandle();
-  if (status != WIFI_SUCCESS || !wlan_interface_handle_) {
-    LOG(ERROR) << "Failed to retrieve wlan interface handle";
-    return status;
-  }
-  LOG(DEBUG) << "Legacy HAL start complete";
-  is_started_ = true;
-  return WIFI_SUCCESS;
-}
-
-wifi_error WifiLegacyHal::stop(
-    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
-    const std::function<void()>& on_stop_complete_user_callback) {
-  if (!is_started_) {
-    LOG(DEBUG) << "Legacy HAL already stopped";
-    on_stop_complete_user_callback();
-    return WIFI_SUCCESS;
-  }
-  LOG(DEBUG) << "Stopping legacy HAL";
-  on_stop_complete_internal_callback =
-      [on_stop_complete_user_callback, this](wifi_handle handle) {
-    CHECK_EQ(global_handle_, handle) << "Handle mismatch";
-    LOG(INFO) << "Legacy HAL stop complete callback received";
-    // Invalidate all the internal pointers now that the HAL is
-    // stopped.
-    invalidate();
-    iface_tool_.SetWifiUpState(false);
-    on_stop_complete_user_callback();
-    is_started_ = false;
-  };
-  awaiting_event_loop_termination_ = true;
-  global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete);
-  const auto status = stop_wait_cv_.wait_for(
-      *lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs),
-      [this] { return !awaiting_event_loop_termination_; });
-  if (!status) {
-    LOG(ERROR) << "Legacy HAL stop failed or timed out";
-    return WIFI_ERROR_UNKNOWN;
-  }
-  LOG(DEBUG) << "Legacy HAL stop complete";
-  return WIFI_SUCCESS;
-}
-
-std::string WifiLegacyHal::getApIfaceName() {
-  // Fake name. This interface does not exist in legacy HAL
-  // API's.
-  return "ap0";
-}
-
-std::string WifiLegacyHal::getNanIfaceName() {
-  // Fake name. This interface does not exist in legacy HAL
-  // API's.
-  return "nan0";
-}
-
-std::string WifiLegacyHal::getP2pIfaceName() {
-  std::array<char, PROPERTY_VALUE_MAX> buffer;
-  property_get("wifi.direct.interface", buffer.data(), "p2p0");
-  return buffer.data();
-}
-
-std::string WifiLegacyHal::getStaIfaceName() {
-  std::array<char, PROPERTY_VALUE_MAX> buffer;
-  property_get("wifi.interface", buffer.data(), "wlan0");
-  return buffer.data();
-}
-
-std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion() {
-  std::array<char, kMaxVersionStringLength> buffer;
-  buffer.fill(0);
-  wifi_error status = global_func_table_.wifi_get_driver_version(
-      wlan_interface_handle_, buffer.data(), buffer.size());
-  return {status, buffer.data()};
-}
-
-std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion() {
-  std::array<char, kMaxVersionStringLength> buffer;
-  buffer.fill(0);
-  wifi_error status = global_func_table_.wifi_get_firmware_version(
-      wlan_interface_handle_, buffer.data(), buffer.size());
-  return {status, buffer.data()};
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::requestDriverMemoryDump() {
-  std::vector<uint8_t> driver_dump;
-  on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer,
-                                                           int buffer_size) {
-    driver_dump.insert(driver_dump.end(),
-                       reinterpret_cast<uint8_t*>(buffer),
-                       reinterpret_cast<uint8_t*>(buffer) + buffer_size);
-  };
-  wifi_error status = global_func_table_.wifi_get_driver_memory_dump(
-      wlan_interface_handle_, {onSyncDriverMemoryDump});
-  on_driver_memory_dump_internal_callback = nullptr;
-  return {status, std::move(driver_dump)};
-}
-
-std::pair<wifi_error, std::vector<uint8_t>>
-WifiLegacyHal::requestFirmwareMemoryDump() {
-  std::vector<uint8_t> firmware_dump;
-  on_firmware_memory_dump_internal_callback = [&firmware_dump](
-      char* buffer, int buffer_size) {
-    firmware_dump.insert(firmware_dump.end(),
-                         reinterpret_cast<uint8_t*>(buffer),
-                         reinterpret_cast<uint8_t*>(buffer) + buffer_size);
-  };
-  wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
-      wlan_interface_handle_, {onSyncFirmwareMemoryDump});
-  on_firmware_memory_dump_internal_callback = nullptr;
-  return {status, std::move(firmware_dump)};
-}
-
-std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet() {
-  feature_set set;
-  static_assert(sizeof(set) == sizeof(uint32_t),
-                "Some features can not be represented in output");
-  wifi_error status = global_func_table_.wifi_get_supported_feature_set(
-      wlan_interface_handle_, &set);
-  return {status, static_cast<uint32_t>(set)};
-}
-
-std::pair<wifi_error, PacketFilterCapabilities>
-WifiLegacyHal::getPacketFilterCapabilities() {
-  PacketFilterCapabilities caps;
-  wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
-      wlan_interface_handle_, &caps.version, &caps.max_len);
-  return {status, caps};
-}
-
-wifi_error WifiLegacyHal::setPacketFilter(const std::vector<uint8_t>& program) {
-  return global_func_table_.wifi_set_packet_filter(
-      wlan_interface_handle_, program.data(), program.size());
-}
-
-std::pair<wifi_error, wifi_gscan_capabilities>
-WifiLegacyHal::getGscanCapabilities() {
-  wifi_gscan_capabilities caps;
-  wifi_error status = global_func_table_.wifi_get_gscan_capabilities(
-      wlan_interface_handle_, &caps);
-  return {status, caps};
-}
-
-wifi_error WifiLegacyHal::startGscan(
-    wifi_request_id id,
-    const wifi_scan_cmd_params& params,
-    const std::function<void(wifi_request_id)>& on_failure_user_callback,
-    const on_gscan_results_callback& on_results_user_callback,
-    const on_gscan_full_result_callback& on_full_result_user_callback) {
-  // If there is already an ongoing background scan, reject new scan requests.
-  if (on_gscan_event_internal_callback ||
-      on_gscan_full_result_internal_callback) {
-    return WIFI_ERROR_NOT_AVAILABLE;
-  }
-
-  // This callback will be used to either trigger |on_results_user_callback| or
-  // |on_failure_user_callback|.
-  on_gscan_event_internal_callback =
-      [on_failure_user_callback, on_results_user_callback, this](
-          wifi_request_id id, wifi_scan_event event) {
-        switch (event) {
-          case WIFI_SCAN_RESULTS_AVAILABLE:
-          case WIFI_SCAN_THRESHOLD_NUM_SCANS:
-          case WIFI_SCAN_THRESHOLD_PERCENT: {
-            wifi_error status;
-            std::vector<wifi_cached_scan_results> cached_scan_results;
-            std::tie(status, cached_scan_results) = getGscanCachedResults();
-            if (status == WIFI_SUCCESS) {
-              on_results_user_callback(id, cached_scan_results);
-              return;
-            }
-          }
-          // Fall through if failed. Failure to retrieve cached scan results
-          // should trigger a background scan failure.
-          case WIFI_SCAN_FAILED:
-            on_failure_user_callback(id);
-            on_gscan_event_internal_callback = nullptr;
-            on_gscan_full_result_internal_callback = nullptr;
-            return;
-        }
-        LOG(FATAL) << "Unexpected gscan event received: " << event;
-      };
-
-  on_gscan_full_result_internal_callback = [on_full_result_user_callback](
-      wifi_request_id id, wifi_scan_result* result, uint32_t buckets_scanned) {
-    if (result) {
-      on_full_result_user_callback(id, result, buckets_scanned);
-    }
-  };
-
-  wifi_scan_result_handler handler = {onAsyncGscanFullResult,
-                                      onAsyncGscanEvent};
-  wifi_error status = global_func_table_.wifi_start_gscan(
-      id, wlan_interface_handle_, params, handler);
-  if (status != WIFI_SUCCESS) {
-    on_gscan_event_internal_callback = nullptr;
-    on_gscan_full_result_internal_callback = nullptr;
-  }
-  return status;
-}
-
-wifi_error WifiLegacyHal::stopGscan(wifi_request_id id) {
-  // If there is no an ongoing background scan, reject stop requests.
-  // TODO(b/32337212): This needs to be handled by the HIDL object because we
-  // need to return the NOT_STARTED error code.
-  if (!on_gscan_event_internal_callback &&
-      !on_gscan_full_result_internal_callback) {
-    return WIFI_ERROR_NOT_AVAILABLE;
-  }
-  wifi_error status =
-      global_func_table_.wifi_stop_gscan(id, wlan_interface_handle_);
-  // If the request Id is wrong, don't stop the ongoing background scan. Any
-  // other error should be treated as the end of background scan.
-  if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
-    on_gscan_event_internal_callback = nullptr;
-    on_gscan_full_result_internal_callback = nullptr;
-  }
-  return status;
-}
-
-std::pair<wifi_error, std::vector<uint32_t>>
-WifiLegacyHal::getValidFrequenciesForBand(wifi_band band) {
-  static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
-                "Wifi Channel cannot be represented in output");
-  std::vector<uint32_t> freqs;
-  freqs.resize(kMaxGscanFrequenciesForBand);
-  int32_t num_freqs = 0;
-  wifi_error status = global_func_table_.wifi_get_valid_channels(
-      wlan_interface_handle_,
-      band,
-      freqs.size(),
-      reinterpret_cast<wifi_channel*>(freqs.data()),
-      &num_freqs);
-  CHECK(num_freqs >= 0 &&
-        static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
-  freqs.resize(num_freqs);
-  return {status, std::move(freqs)};
-}
-
-wifi_error WifiLegacyHal::setDfsFlag(bool dfs_on) {
-  return global_func_table_.wifi_set_nodfs_flag(
-      wlan_interface_handle_, dfs_on ? 0 : 1);
-}
-
-wifi_error WifiLegacyHal::enableLinkLayerStats(bool debug) {
-  wifi_link_layer_params params;
-  params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
-  params.aggressive_statistics_gathering = debug;
-  return global_func_table_.wifi_set_link_stats(wlan_interface_handle_, params);
-}
-
-wifi_error WifiLegacyHal::disableLinkLayerStats() {
-  // TODO: Do we care about these responses?
-  uint32_t clear_mask_rsp;
-  uint8_t stop_rsp;
-  return global_func_table_.wifi_clear_link_stats(
-      wlan_interface_handle_, 0xFFFFFFFF, &clear_mask_rsp, 1, &stop_rsp);
-}
-
-std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats() {
-  LinkLayerStats link_stats{};
-  LinkLayerStats* link_stats_ptr = &link_stats;
-
-  on_link_layer_stats_result_internal_callback =
-      [&link_stats_ptr](wifi_request_id /* id */,
-                        wifi_iface_stat* iface_stats_ptr,
-                        int num_radios,
-                        wifi_radio_stat* radio_stats_ptr) {
-        if (iface_stats_ptr != nullptr) {
-          link_stats_ptr->iface = *iface_stats_ptr;
-          link_stats_ptr->iface.num_peers = 0;
-        } else {
-          LOG(ERROR) << "Invalid iface stats in link layer stats";
-        }
-        if (num_radios <= 0 || radio_stats_ptr == nullptr) {
-          LOG(ERROR) << "Invalid radio stats in link layer stats";
-          return;
-        }
-        for (int i = 0; i < num_radios; i++) {
-          LinkLayerRadioStats radio;
-          radio.stats = radio_stats_ptr[i];
-          // Copy over the tx level array to the separate vector.
-          if (radio_stats_ptr[i].num_tx_levels > 0 &&
-              radio_stats_ptr[i].tx_time_per_levels != nullptr) {
-            radio.tx_time_per_levels.assign(
-                radio_stats_ptr[i].tx_time_per_levels,
-                radio_stats_ptr[i].tx_time_per_levels +
-                    radio_stats_ptr[i].num_tx_levels);
-          }
-          radio.stats.num_tx_levels = 0;
-          radio.stats.tx_time_per_levels = nullptr;
-          link_stats_ptr->radios.push_back(radio);
-        }
-      };
-
-  wifi_error status = global_func_table_.wifi_get_link_stats(
-      0, wlan_interface_handle_, {onSyncLinkLayerStatsResult});
-  on_link_layer_stats_result_internal_callback = nullptr;
-  return {status, link_stats};
-}
-
-wifi_error WifiLegacyHal::startRssiMonitoring(
-    wifi_request_id id,
-    int8_t max_rssi,
-    int8_t min_rssi,
-    const on_rssi_threshold_breached_callback&
-        on_threshold_breached_user_callback) {
-  if (on_rssi_threshold_breached_internal_callback) {
-    return WIFI_ERROR_NOT_AVAILABLE;
-  }
-  on_rssi_threshold_breached_internal_callback =
-      [on_threshold_breached_user_callback](
-          wifi_request_id id, uint8_t* bssid_ptr, int8_t rssi) {
-        if (!bssid_ptr) {
-          return;
-        }
-        std::array<uint8_t, 6> bssid_arr;
-        // |bssid_ptr| pointer is assumed to have 6 bytes for the mac address.
-        std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
-        on_threshold_breached_user_callback(id, bssid_arr, rssi);
-      };
-  wifi_error status = global_func_table_.wifi_start_rssi_monitoring(
-      id,
-      wlan_interface_handle_,
-      max_rssi,
-      min_rssi,
-      {onAsyncRssiThresholdBreached});
-  if (status != WIFI_SUCCESS) {
-    on_rssi_threshold_breached_internal_callback = nullptr;
-  }
-  return status;
-}
-
-wifi_error WifiLegacyHal::stopRssiMonitoring(wifi_request_id id) {
-  if (!on_rssi_threshold_breached_internal_callback) {
-    return WIFI_ERROR_NOT_AVAILABLE;
-  }
-  wifi_error status =
-      global_func_table_.wifi_stop_rssi_monitoring(id, wlan_interface_handle_);
-  // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
-  // other error should be treated as the end of background scan.
-  if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
-    on_rssi_threshold_breached_internal_callback = nullptr;
-  }
-  return status;
-}
-
-std::pair<wifi_error, wifi_roaming_capabilities>
-WifiLegacyHal::getRoamingCapabilities() {
-  wifi_roaming_capabilities caps;
-  wifi_error status = global_func_table_.wifi_get_roaming_capabilities(
-      wlan_interface_handle_, &caps);
-  return {status, caps};
-}
-
-wifi_error WifiLegacyHal::configureRoaming(const wifi_roaming_config& config) {
-  wifi_roaming_config config_internal = config;
-  return global_func_table_.wifi_configure_roaming(wlan_interface_handle_,
-                                                   &config_internal);
-}
-
-wifi_error WifiLegacyHal::enableFirmwareRoaming(fw_roaming_state_t state) {
-  return global_func_table_.wifi_enable_firmware_roaming(wlan_interface_handle_,
-                                                         state);
-}
-
-wifi_error WifiLegacyHal::configureNdOffload(bool enable) {
-  return global_func_table_.wifi_configure_nd_offload(wlan_interface_handle_,
-                                                      enable);
-}
-
-wifi_error WifiLegacyHal::startSendingOffloadedPacket(
-    uint32_t cmd_id,
-    const std::vector<uint8_t>& ip_packet_data,
-    const std::array<uint8_t, 6>& src_address,
-    const std::array<uint8_t, 6>& dst_address,
-    uint32_t period_in_ms) {
-  std::vector<uint8_t> ip_packet_data_internal(ip_packet_data);
-  std::vector<uint8_t> src_address_internal(
-      src_address.data(), src_address.data() + src_address.size());
-  std::vector<uint8_t> dst_address_internal(
-      dst_address.data(), dst_address.data() + dst_address.size());
-  return global_func_table_.wifi_start_sending_offloaded_packet(
-      cmd_id,
-      wlan_interface_handle_,
-      ip_packet_data_internal.data(),
-      ip_packet_data_internal.size(),
-      src_address_internal.data(),
-      dst_address_internal.data(),
-      period_in_ms);
-}
-
-wifi_error WifiLegacyHal::stopSendingOffloadedPacket(uint32_t cmd_id) {
-  return global_func_table_.wifi_stop_sending_offloaded_packet(
-      cmd_id, wlan_interface_handle_);
-}
-
-wifi_error WifiLegacyHal::setScanningMacOui(const std::array<uint8_t, 3>& oui) {
-  std::vector<uint8_t> oui_internal(oui.data(), oui.data() + oui.size());
-  return global_func_table_.wifi_set_scanning_mac_oui(wlan_interface_handle_,
-                                                      oui_internal.data());
-}
-
-wifi_error WifiLegacyHal::selectTxPowerScenario(wifi_power_scenario scenario) {
-  return global_func_table_.wifi_select_tx_power_scenario(
-      wlan_interface_handle_, scenario);
-}
-
-wifi_error WifiLegacyHal::resetTxPowerScenario() {
-  return global_func_table_.wifi_reset_tx_power_scenario(wlan_interface_handle_);
-}
-
-std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet() {
-  uint32_t supported_features;
-  wifi_error status = global_func_table_.wifi_get_logger_supported_feature_set(
-      wlan_interface_handle_, &supported_features);
-  return {status, supported_features};
-}
-
-wifi_error WifiLegacyHal::startPktFateMonitoring() {
-  return global_func_table_.wifi_start_pkt_fate_monitoring(
-      wlan_interface_handle_);
-}
-
-std::pair<wifi_error, std::vector<wifi_tx_report>>
-WifiLegacyHal::getTxPktFates() {
-  std::vector<wifi_tx_report> tx_pkt_fates;
-  tx_pkt_fates.resize(MAX_FATE_LOG_LEN);
-  size_t num_fates = 0;
-  wifi_error status =
-      global_func_table_.wifi_get_tx_pkt_fates(wlan_interface_handle_,
-                                               tx_pkt_fates.data(),
-                                               tx_pkt_fates.size(),
-                                               &num_fates);
-  CHECK(num_fates <= MAX_FATE_LOG_LEN);
-  tx_pkt_fates.resize(num_fates);
-  return {status, std::move(tx_pkt_fates)};
-}
-
-std::pair<wifi_error, std::vector<wifi_rx_report>>
-WifiLegacyHal::getRxPktFates() {
-  std::vector<wifi_rx_report> rx_pkt_fates;
-  rx_pkt_fates.resize(MAX_FATE_LOG_LEN);
-  size_t num_fates = 0;
-  wifi_error status =
-      global_func_table_.wifi_get_rx_pkt_fates(wlan_interface_handle_,
-                                               rx_pkt_fates.data(),
-                                               rx_pkt_fates.size(),
-                                               &num_fates);
-  CHECK(num_fates <= MAX_FATE_LOG_LEN);
-  rx_pkt_fates.resize(num_fates);
-  return {status, std::move(rx_pkt_fates)};
-}
-
-std::pair<wifi_error, WakeReasonStats> WifiLegacyHal::getWakeReasonStats() {
-  WakeReasonStats stats;
-  stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
-  stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
-
-  // This legacy struct needs separate memory to store the variable sized wake
-  // reason types.
-  stats.wake_reason_cnt.cmd_event_wake_cnt =
-      reinterpret_cast<int32_t*>(stats.cmd_event_wake_cnt.data());
-  stats.wake_reason_cnt.cmd_event_wake_cnt_sz = stats.cmd_event_wake_cnt.size();
-  stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0;
-  stats.wake_reason_cnt.driver_fw_local_wake_cnt =
-      reinterpret_cast<int32_t*>(stats.driver_fw_local_wake_cnt.data());
-  stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz =
-      stats.driver_fw_local_wake_cnt.size();
-  stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
-
-  wifi_error status = global_func_table_.wifi_get_wake_reason_stats(
-      wlan_interface_handle_, &stats.wake_reason_cnt);
-
-  CHECK(stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 &&
-        static_cast<uint32_t>(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <=
-            kMaxWakeReasonStatsArraySize);
-  stats.cmd_event_wake_cnt.resize(
-      stats.wake_reason_cnt.cmd_event_wake_cnt_used);
-  stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr;
-
-  CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 &&
-        static_cast<uint32_t>(
-            stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <=
-            kMaxWakeReasonStatsArraySize);
-  stats.driver_fw_local_wake_cnt.resize(
-      stats.wake_reason_cnt.driver_fw_local_wake_cnt_used);
-  stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr;
-
-  return {status, stats};
-}
-
-wifi_error WifiLegacyHal::registerRingBufferCallbackHandler(
-    const on_ring_buffer_data_callback& on_user_data_callback) {
-  if (on_ring_buffer_data_internal_callback) {
-    return WIFI_ERROR_NOT_AVAILABLE;
-  }
-  on_ring_buffer_data_internal_callback = [on_user_data_callback](
-      char* ring_name,
-      char* buffer,
-      int buffer_size,
-      wifi_ring_buffer_status* status) {
-    if (status && buffer) {
-      std::vector<uint8_t> buffer_vector(
-          reinterpret_cast<uint8_t*>(buffer),
-          reinterpret_cast<uint8_t*>(buffer) + buffer_size);
-      on_user_data_callback(ring_name, buffer_vector, *status);
-    }
-  };
-  wifi_error status = global_func_table_.wifi_set_log_handler(
-      0, wlan_interface_handle_, {onAsyncRingBufferData});
-  if (status != WIFI_SUCCESS) {
-    on_ring_buffer_data_internal_callback = nullptr;
-  }
-  return status;
-}
-
-wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler() {
-  if (!on_ring_buffer_data_internal_callback) {
-    return WIFI_ERROR_NOT_AVAILABLE;
-  }
-  on_ring_buffer_data_internal_callback = nullptr;
-  return global_func_table_.wifi_reset_log_handler(0, wlan_interface_handle_);
-}
-
-std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
-WifiLegacyHal::getRingBuffersStatus() {
-  std::vector<wifi_ring_buffer_status> ring_buffers_status;
-  ring_buffers_status.resize(kMaxRingBuffers);
-  uint32_t num_rings = kMaxRingBuffers;
-  wifi_error status = global_func_table_.wifi_get_ring_buffers_status(
-      wlan_interface_handle_, &num_rings, ring_buffers_status.data());
-  CHECK(num_rings <= kMaxRingBuffers);
-  ring_buffers_status.resize(num_rings);
-  return {status, std::move(ring_buffers_status)};
-}
-
-wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& ring_name,
-                                                 uint32_t verbose_level,
-                                                 uint32_t max_interval_sec,
-                                                 uint32_t min_data_size) {
-  return global_func_table_.wifi_start_logging(wlan_interface_handle_,
-                                               verbose_level,
-                                               0,
-                                               max_interval_sec,
-                                               min_data_size,
-                                               makeCharVec(ring_name).data());
-}
-
-wifi_error WifiLegacyHal::getRingBufferData(const std::string& ring_name) {
-  return global_func_table_.wifi_get_ring_data(wlan_interface_handle_,
-                                               makeCharVec(ring_name).data());
-}
-
-wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
-    const on_error_alert_callback& on_user_alert_callback) {
-  if (on_error_alert_internal_callback) {
-    return WIFI_ERROR_NOT_AVAILABLE;
-  }
-  on_error_alert_internal_callback = [on_user_alert_callback](
-      wifi_request_id id, char* buffer, int buffer_size, int err_code) {
-    if (buffer) {
-      CHECK(id == 0);
-      on_user_alert_callback(
-          err_code,
-          std::vector<uint8_t>(
-              reinterpret_cast<uint8_t*>(buffer),
-              reinterpret_cast<uint8_t*>(buffer) + buffer_size));
-    }
-  };
-  wifi_error status = global_func_table_.wifi_set_alert_handler(
-      0, wlan_interface_handle_, {onAsyncErrorAlert});
-  if (status != WIFI_SUCCESS) {
-    on_error_alert_internal_callback = nullptr;
-  }
-  return status;
-}
-
-wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler() {
-  if (!on_error_alert_internal_callback) {
-    return WIFI_ERROR_NOT_AVAILABLE;
-  }
-  on_error_alert_internal_callback = nullptr;
-  return global_func_table_.wifi_reset_alert_handler(0, wlan_interface_handle_);
-}
-
-wifi_error WifiLegacyHal::startRttRangeRequest(
-    wifi_request_id id,
-    const std::vector<wifi_rtt_config>& rtt_configs,
-    const on_rtt_results_callback& on_results_user_callback) {
-  if (on_rtt_results_internal_callback) {
-    return WIFI_ERROR_NOT_AVAILABLE;
-  }
-
-  on_rtt_results_internal_callback = [on_results_user_callback](
-      wifi_request_id id,
-      unsigned num_results,
-      wifi_rtt_result* rtt_results[]) {
-    if (num_results > 0 && !rtt_results) {
-      LOG(ERROR) << "Unexpected nullptr in RTT results";
-      return;
-    }
-    std::vector<const wifi_rtt_result*> rtt_results_vec;
-    std::copy_if(
-        rtt_results,
-        rtt_results + num_results,
-        back_inserter(rtt_results_vec),
-        [](wifi_rtt_result* rtt_result) { return rtt_result != nullptr; });
-    on_results_user_callback(id, rtt_results_vec);
-  };
-
-  std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
-  wifi_error status =
-      global_func_table_.wifi_rtt_range_request(id,
-                                                wlan_interface_handle_,
-                                                rtt_configs.size(),
-                                                rtt_configs_internal.data(),
-                                                {onAsyncRttResults});
-  if (status != WIFI_SUCCESS) {
-    on_rtt_results_internal_callback = nullptr;
-  }
-  return status;
-}
-
-wifi_error WifiLegacyHal::cancelRttRangeRequest(
-    wifi_request_id id, const std::vector<std::array<uint8_t, 6>>& mac_addrs) {
-  if (!on_rtt_results_internal_callback) {
-    return WIFI_ERROR_NOT_AVAILABLE;
-  }
-  static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, 6>),
-                "MAC address size mismatch");
-  // TODO: How do we handle partial cancels (i.e only a subset of enabled mac
-  // addressed are cancelled).
-  std::vector<std::array<uint8_t, 6>> mac_addrs_internal(mac_addrs);
-  wifi_error status = global_func_table_.wifi_rtt_range_cancel(
-      id,
-      wlan_interface_handle_,
-      mac_addrs.size(),
-      reinterpret_cast<mac_addr*>(mac_addrs_internal.data()));
-  // If the request Id is wrong, don't stop the ongoing range request. Any
-  // other error should be treated as the end of rtt ranging.
-  if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
-    on_rtt_results_internal_callback = nullptr;
-  }
-  return status;
-}
-
-std::pair<wifi_error, wifi_rtt_capabilities>
-WifiLegacyHal::getRttCapabilities() {
-  wifi_rtt_capabilities rtt_caps;
-  wifi_error status = global_func_table_.wifi_get_rtt_capabilities(
-      wlan_interface_handle_, &rtt_caps);
-  return {status, rtt_caps};
-}
-
-std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo() {
-  wifi_rtt_responder rtt_responder;
-  wifi_error status = global_func_table_.wifi_rtt_get_responder_info(
-      wlan_interface_handle_, &rtt_responder);
-  return {status, rtt_responder};
-}
-
-wifi_error WifiLegacyHal::enableRttResponder(
-    wifi_request_id id,
-    const wifi_channel_info& channel_hint,
-    uint32_t max_duration_secs,
-    const wifi_rtt_responder& info) {
-  wifi_rtt_responder info_internal(info);
-  return global_func_table_.wifi_enable_responder(id,
-                                                  wlan_interface_handle_,
-                                                  channel_hint,
-                                                  max_duration_secs,
-                                                  &info_internal);
-}
-
-wifi_error WifiLegacyHal::disableRttResponder(wifi_request_id id) {
-  return global_func_table_.wifi_disable_responder(id, wlan_interface_handle_);
-}
-
-wifi_error WifiLegacyHal::setRttLci(wifi_request_id id,
-                                    const wifi_lci_information& info) {
-  wifi_lci_information info_internal(info);
-  return global_func_table_.wifi_set_lci(
-      id, wlan_interface_handle_, &info_internal);
-}
-
-wifi_error WifiLegacyHal::setRttLcr(wifi_request_id id,
-                                    const wifi_lcr_information& info) {
-  wifi_lcr_information info_internal(info);
-  return global_func_table_.wifi_set_lcr(
-      id, wlan_interface_handle_, &info_internal);
-}
-
-wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(
-    const NanCallbackHandlers& user_callbacks) {
-  on_nan_notify_response_user_callback = user_callbacks.on_notify_response;
-  on_nan_event_publish_terminated_user_callback =
-      user_callbacks.on_event_publish_terminated;
-  on_nan_event_match_user_callback = user_callbacks.on_event_match;
-  on_nan_event_match_expired_user_callback =
-      user_callbacks.on_event_match_expired;
-  on_nan_event_subscribe_terminated_user_callback =
-      user_callbacks.on_event_subscribe_terminated;
-  on_nan_event_followup_user_callback = user_callbacks.on_event_followup;
-  on_nan_event_disc_eng_event_user_callback =
-      user_callbacks.on_event_disc_eng_event;
-  on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled;
-  on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
-  on_nan_event_beacon_sdf_payload_user_callback =
-      user_callbacks.on_event_beacon_sdf_payload;
-  on_nan_event_data_path_request_user_callback =
-      user_callbacks.on_event_data_path_request;
-  on_nan_event_data_path_confirm_user_callback =
-      user_callbacks.on_event_data_path_confirm;
-  on_nan_event_data_path_end_user_callback =
-      user_callbacks.on_event_data_path_end;
-  on_nan_event_transmit_follow_up_user_callback =
-      user_callbacks.on_event_transmit_follow_up;
-  on_nan_event_range_request_user_callback =
-      user_callbacks.on_event_range_request;
-  on_nan_event_range_report_user_callback =
-      user_callbacks.on_event_range_report;
-
-  return global_func_table_.wifi_nan_register_handler(
-      wlan_interface_handle_,
-      {onAysncNanNotifyResponse,
-       onAysncNanEventPublishReplied,
-       onAysncNanEventPublishTerminated,
-       onAysncNanEventMatch,
-       onAysncNanEventMatchExpired,
-       onAysncNanEventSubscribeTerminated,
-       onAysncNanEventFollowup,
-       onAysncNanEventDiscEngEvent,
-       onAysncNanEventDisabled,
-       onAysncNanEventTca,
-       onAysncNanEventBeaconSdfPayload,
-       onAysncNanEventDataPathRequest,
-       onAysncNanEventDataPathConfirm,
-       onAysncNanEventDataPathEnd,
-       onAysncNanEventTransmitFollowUp,
-       onAysncNanEventRangeRequest,
-       onAysncNanEventRangeReport});
-}
-
-wifi_error WifiLegacyHal::nanEnableRequest(transaction_id id,
-                                           const NanEnableRequest& msg) {
-  NanEnableRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_enable_request(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanDisableRequest(transaction_id id) {
-  return global_func_table_.wifi_nan_disable_request(id,
-                                                     wlan_interface_handle_);
-}
-
-wifi_error WifiLegacyHal::nanPublishRequest(transaction_id id,
-                                            const NanPublishRequest& msg) {
-  NanPublishRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_publish_request(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanPublishCancelRequest(
-    transaction_id id, const NanPublishCancelRequest& msg) {
-  NanPublishCancelRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_publish_cancel_request(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanSubscribeRequest(transaction_id id,
-                                              const NanSubscribeRequest& msg) {
-  NanSubscribeRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_subscribe_request(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanSubscribeCancelRequest(
-    transaction_id id, const NanSubscribeCancelRequest& msg) {
-  NanSubscribeCancelRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_subscribe_cancel_request(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanTransmitFollowupRequest(
-    transaction_id id, const NanTransmitFollowupRequest& msg) {
-  NanTransmitFollowupRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_transmit_followup_request(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanStatsRequest(transaction_id id,
-                                          const NanStatsRequest& msg) {
-  NanStatsRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_stats_request(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanConfigRequest(transaction_id id,
-                                           const NanConfigRequest& msg) {
-  NanConfigRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_config_request(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanTcaRequest(transaction_id id,
-                                        const NanTCARequest& msg) {
-  NanTCARequest msg_internal(msg);
-  return global_func_table_.wifi_nan_tca_request(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(
-    transaction_id id, const NanBeaconSdfPayloadRequest& msg) {
-  NanBeaconSdfPayloadRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_beacon_sdf_payload_request(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-std::pair<wifi_error, NanVersion> WifiLegacyHal::nanGetVersion() {
-  NanVersion version;
-  wifi_error status =
-      global_func_table_.wifi_nan_get_version(global_handle_, &version);
-  return {status, version};
-}
-
-wifi_error WifiLegacyHal::nanGetCapabilities(transaction_id id) {
-  return global_func_table_.wifi_nan_get_capabilities(id,
-                                                      wlan_interface_handle_);
-}
-
-wifi_error WifiLegacyHal::nanDataInterfaceCreate(
-    transaction_id id, const std::string& iface_name) {
-  return global_func_table_.wifi_nan_data_interface_create(
-      id, wlan_interface_handle_, makeCharVec(iface_name).data());
-}
-
-wifi_error WifiLegacyHal::nanDataInterfaceDelete(
-    transaction_id id, const std::string& iface_name) {
-  return global_func_table_.wifi_nan_data_interface_delete(
-      id, wlan_interface_handle_, makeCharVec(iface_name).data());
-}
-
-wifi_error WifiLegacyHal::nanDataRequestInitiator(
-    transaction_id id, const NanDataPathInitiatorRequest& msg) {
-  NanDataPathInitiatorRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_data_request_initiator(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-wifi_error WifiLegacyHal::nanDataIndicationResponse(
-    transaction_id id, const NanDataPathIndicationResponse& msg) {
-  NanDataPathIndicationResponse msg_internal(msg);
-  return global_func_table_.wifi_nan_data_indication_response(
-      id, wlan_interface_handle_, &msg_internal);
-}
-
-typedef struct {
-    u8 num_ndp_instances;
-    NanDataPathId ndp_instance_id;
-} NanDataPathEndSingleNdpIdRequest;
-
-wifi_error WifiLegacyHal::nanDataEnd(transaction_id id,
-                                     uint32_t ndpInstanceId) {
-  NanDataPathEndSingleNdpIdRequest msg;
-  msg.num_ndp_instances = 1;
-  msg.ndp_instance_id = ndpInstanceId;
-  wifi_error status = global_func_table_.wifi_nan_data_end(
-      id, wlan_interface_handle_, (NanDataPathEndRequest*)&msg);
-  return status;
-}
-
-wifi_error WifiLegacyHal::setCountryCode(std::array<int8_t, 2> code) {
-  std::string code_str(code.data(), code.data() + code.size());
-  return global_func_table_.wifi_set_country_code(wlan_interface_handle_,
-                                                  code_str.c_str());
-}
-
-wifi_error WifiLegacyHal::retrieveWlanInterfaceHandle() {
-  const std::string& ifname_to_find = getStaIfaceName();
-  wifi_interface_handle* iface_handles = nullptr;
-  int num_iface_handles = 0;
-  wifi_error status = global_func_table_.wifi_get_ifaces(
-      global_handle_, &num_iface_handles, &iface_handles);
-  if (status != WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to enumerate interface handles";
-    return status;
-  }
-  for (int i = 0; i < num_iface_handles; ++i) {
-    std::array<char, IFNAMSIZ> current_ifname;
-    current_ifname.fill(0);
-    status = global_func_table_.wifi_get_iface_name(
-        iface_handles[i], current_ifname.data(), current_ifname.size());
-    if (status != WIFI_SUCCESS) {
-      LOG(WARNING) << "Failed to get interface handle name";
-      continue;
-    }
-    if (ifname_to_find == current_ifname.data()) {
-      wlan_interface_handle_ = iface_handles[i];
-      return WIFI_SUCCESS;
-    }
-  }
-  return WIFI_ERROR_UNKNOWN;
-}
-
-void WifiLegacyHal::runEventLoop() {
-  LOG(DEBUG) << "Starting legacy HAL event loop";
-  global_func_table_.wifi_event_loop(global_handle_);
-  const auto lock = hidl_sync_util::acquireGlobalLock();
-  if (!awaiting_event_loop_termination_) {
-    LOG(FATAL) << "Legacy HAL event loop terminated, but HAL was not stopping";
-  }
-  LOG(DEBUG) << "Legacy HAL event loop terminated";
-  awaiting_event_loop_termination_ = false;
-  stop_wait_cv_.notify_one();
-}
-
-std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
-WifiLegacyHal::getGscanCachedResults() {
-  std::vector<wifi_cached_scan_results> cached_scan_results;
-  cached_scan_results.resize(kMaxCachedGscanResults);
-  int32_t num_results = 0;
-  wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
-      wlan_interface_handle_,
-      true /* always flush */,
-      cached_scan_results.size(),
-      cached_scan_results.data(),
-      &num_results);
-  CHECK(num_results >= 0 &&
-        static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
-  cached_scan_results.resize(num_results);
-  // Check for invalid IE lengths in these cached scan results and correct it.
-  for (auto& cached_scan_result : cached_scan_results) {
-    int num_scan_results = cached_scan_result.num_results;
-    for (int i = 0; i < num_scan_results; i++) {
-      auto& scan_result = cached_scan_result.results[i];
-      if (scan_result.ie_length > 0) {
-        LOG(DEBUG) << "Cached scan result has non-zero IE length "
-                   << scan_result.ie_length;
-        scan_result.ie_length = 0;
-      }
-    }
-  }
-  return {status, std::move(cached_scan_results)};
-}
-
-void WifiLegacyHal::invalidate() {
-  global_handle_ = nullptr;
-  wlan_interface_handle_ = nullptr;
-  on_driver_memory_dump_internal_callback = nullptr;
-  on_firmware_memory_dump_internal_callback = nullptr;
-  on_gscan_event_internal_callback = nullptr;
-  on_gscan_full_result_internal_callback = nullptr;
-  on_link_layer_stats_result_internal_callback = nullptr;
-  on_rssi_threshold_breached_internal_callback = nullptr;
-  on_ring_buffer_data_internal_callback = nullptr;
-  on_error_alert_internal_callback = nullptr;
-  on_rtt_results_internal_callback = nullptr;
-  on_nan_notify_response_user_callback = nullptr;
-  on_nan_event_publish_terminated_user_callback = nullptr;
-  on_nan_event_match_user_callback = nullptr;
-  on_nan_event_match_expired_user_callback = nullptr;
-  on_nan_event_subscribe_terminated_user_callback = nullptr;
-  on_nan_event_followup_user_callback = nullptr;
-  on_nan_event_disc_eng_event_user_callback = nullptr;
-  on_nan_event_disabled_user_callback = nullptr;
-  on_nan_event_tca_user_callback = nullptr;
-  on_nan_event_beacon_sdf_payload_user_callback = nullptr;
-  on_nan_event_data_path_request_user_callback = nullptr;
-  on_nan_event_data_path_confirm_user_callback = nullptr;
-  on_nan_event_data_path_end_user_callback = nullptr;
-  on_nan_event_transmit_follow_up_user_callback = nullptr;
-  on_nan_event_range_request_user_callback = nullptr;
-  on_nan_event_range_report_user_callback = nullptr;
-}
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi_legacy_hal.h b/wifi/1.1/default/wifi_legacy_hal.h
deleted file mode 100644
index 5498803..0000000
--- a/wifi/1.1/default/wifi_legacy_hal.h
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * 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 WIFI_LEGACY_HAL_H_
-#define WIFI_LEGACY_HAL_H_
-
-#include <functional>
-#include <thread>
-#include <vector>
-#include <condition_variable>
-
-#include <wifi_system/interface_tool.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-// This is in a separate namespace to prevent typename conflicts between
-// the legacy HAL types and the HIDL interface types.
-namespace legacy_hal {
-// Wrap all the types defined inside the legacy HAL header files inside this
-// namespace.
-#include <hardware_legacy/wifi_hal.h>
-
-// APF capabilities supported by the iface.
-struct PacketFilterCapabilities {
-  uint32_t version;
-  uint32_t max_len;
-};
-
-// WARNING: We don't care about the variable sized members of either
-// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
-// to escape the compiler warnings regarding this.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
-// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
-// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
-// into a separate return element to avoid passing pointers around.
-struct LinkLayerRadioStats {
-  wifi_radio_stat stats;
-  std::vector<uint32_t> tx_time_per_levels;
-};
-
-struct LinkLayerStats {
-  wifi_iface_stat iface;
-  std::vector<LinkLayerRadioStats> radios;
-};
-#pragma GCC diagnostic pop
-
-// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
-// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
-// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
-// API. Separate that out into a separate return elements to avoid passing
-// pointers around.
-struct WakeReasonStats {
-  WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
-  std::vector<uint32_t> cmd_event_wake_cnt;
-  std::vector<uint32_t> driver_fw_local_wake_cnt;
-};
-
-// NAN response and event callbacks struct.
-struct NanCallbackHandlers {
-  // NotifyResponse invoked to notify the status of the Request.
-  std::function<void(transaction_id, const NanResponseMsg&)> on_notify_response;
-  // Various event callbacks.
-  std::function<void(const NanPublishTerminatedInd&)>
-      on_event_publish_terminated;
-  std::function<void(const NanMatchInd&)> on_event_match;
-  std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
-  std::function<void(const NanSubscribeTerminatedInd&)>
-      on_event_subscribe_terminated;
-  std::function<void(const NanFollowupInd&)> on_event_followup;
-  std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
-  std::function<void(const NanDisabledInd&)> on_event_disabled;
-  std::function<void(const NanTCAInd&)> on_event_tca;
-  std::function<void(const NanBeaconSdfPayloadInd&)>
-      on_event_beacon_sdf_payload;
-  std::function<void(const NanDataPathRequestInd&)> on_event_data_path_request;
-  std::function<void(const NanDataPathConfirmInd&)> on_event_data_path_confirm;
-  std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
-  std::function<void(const NanTransmitFollowupInd&)>
-      on_event_transmit_follow_up;
-  std::function<void(const NanRangeRequestInd&)>
-      on_event_range_request;
-  std::function<void(const NanRangeReportInd&)>
-      on_event_range_report;
-};
-
-// Full scan results contain IE info and are hence passed by reference, to
-// preserve the variable length array member |ie_data|. Callee must not retain
-// the pointer.
-using on_gscan_full_result_callback =
-    std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
-// These scan results don't contain any IE info, so no need to pass by
-// reference.
-using on_gscan_results_callback = std::function<void(
-    wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
-
-// Invoked when the rssi value breaches the thresholds set.
-using on_rssi_threshold_breached_callback =
-    std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
-
-// Callback for RTT range request results.
-// Rtt results contain IE info and are hence passed by reference, to
-// preserve the |LCI| and |LCR| pointers. Callee must not retain
-// the pointer.
-using on_rtt_results_callback = std::function<void(
-    wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
-
-// Callback for ring buffer data.
-using on_ring_buffer_data_callback =
-    std::function<void(const std::string&,
-                       const std::vector<uint8_t>&,
-                       const wifi_ring_buffer_status&)>;
-
-// Callback for alerts.
-using on_error_alert_callback =
-    std::function<void(int32_t, const std::vector<uint8_t>&)>;
-/**
- * Class that encapsulates all legacy HAL interactions.
- * This class manages the lifetime of the event loop thread used by legacy HAL.
- *
- * Note: aThere will only be a single instance of this class created in the Wifi
- * object and will be valid for the lifetime of the process.
- */
-class WifiLegacyHal {
- public:
-  WifiLegacyHal();
-  // Names to use for the different types of iface.
-  std::string getApIfaceName();
-  std::string getNanIfaceName();
-  std::string getP2pIfaceName();
-  std::string getStaIfaceName();
-
-  // Initialize the legacy HAL function table.
-  wifi_error initialize();
-  // Start the legacy HAL and the event looper thread.
-  wifi_error start();
-  // Deinitialize the legacy HAL and wait for the event loop thread to exit
-  // using a predefined timeout.
-  wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
-                  const std::function<void()>& on_complete_callback);
-  // Wrappers for all the functions in the legacy HAL function table.
-  std::pair<wifi_error, std::string> getDriverVersion();
-  std::pair<wifi_error, std::string> getFirmwareVersion();
-  std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump();
-  std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump();
-  std::pair<wifi_error, uint32_t> getSupportedFeatureSet();
-  // APF functions.
-  std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities();
-  wifi_error setPacketFilter(const std::vector<uint8_t>& program);
-  // Gscan functions.
-  std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities();
-  // These API's provides a simplified interface over the legacy Gscan API's:
-  // a) All scan events from the legacy HAL API other than the
-  //    |WIFI_SCAN_FAILED| are treated as notification of results.
-  //    This method then retrieves the cached scan results from the legacy
-  //    HAL API and triggers the externally provided |on_results_user_callback|
-  //    on success.
-  // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan results
-  //    triggers the externally provided |on_failure_user_callback|.
-  // c) Full scan result event triggers the externally provided
-  //    |on_full_result_user_callback|.
-  wifi_error startGscan(
-      wifi_request_id id,
-      const wifi_scan_cmd_params& params,
-      const std::function<void(wifi_request_id)>& on_failure_callback,
-      const on_gscan_results_callback& on_results_callback,
-      const on_gscan_full_result_callback& on_full_result_callback);
-  wifi_error stopGscan(wifi_request_id id);
-  std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
-      wifi_band band);
-  wifi_error setDfsFlag(bool dfs_on);
-  // Link layer stats functions.
-  wifi_error enableLinkLayerStats(bool debug);
-  wifi_error disableLinkLayerStats();
-  std::pair<wifi_error, LinkLayerStats> getLinkLayerStats();
-  // RSSI monitor functions.
-  wifi_error startRssiMonitoring(wifi_request_id id,
-                                 int8_t max_rssi,
-                                 int8_t min_rssi,
-                                 const on_rssi_threshold_breached_callback&
-                                     on_threshold_breached_callback);
-  wifi_error stopRssiMonitoring(wifi_request_id id);
-  std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities();
-  wifi_error configureRoaming(const wifi_roaming_config& config);
-  wifi_error enableFirmwareRoaming(fw_roaming_state_t state);
-  wifi_error configureNdOffload(bool enable);
-  wifi_error startSendingOffloadedPacket(
-      uint32_t cmd_id,
-      const std::vector<uint8_t>& ip_packet_data,
-      const std::array<uint8_t, 6>& src_address,
-      const std::array<uint8_t, 6>& dst_address,
-      uint32_t period_in_ms);
-  wifi_error stopSendingOffloadedPacket(uint32_t cmd_id);
-  wifi_error setScanningMacOui(const std::array<uint8_t, 3>& oui);
-  wifi_error selectTxPowerScenario(wifi_power_scenario scenario);
-  wifi_error resetTxPowerScenario();
-  // Logger/debug functions.
-  std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet();
-  wifi_error startPktFateMonitoring();
-  std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates();
-  std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates();
-  std::pair<wifi_error, WakeReasonStats> getWakeReasonStats();
-  wifi_error registerRingBufferCallbackHandler(
-      const on_ring_buffer_data_callback& on_data_callback);
-  wifi_error deregisterRingBufferCallbackHandler();
-  std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
-  getRingBuffersStatus();
-  wifi_error startRingBufferLogging(const std::string& ring_name,
-                                    uint32_t verbose_level,
-                                    uint32_t max_interval_sec,
-                                    uint32_t min_data_size);
-  wifi_error getRingBufferData(const std::string& ring_name);
-  wifi_error registerErrorAlertCallbackHandler(
-      const on_error_alert_callback& on_alert_callback);
-  wifi_error deregisterErrorAlertCallbackHandler();
-  // RTT functions.
-  wifi_error startRttRangeRequest(
-      wifi_request_id id,
-      const std::vector<wifi_rtt_config>& rtt_configs,
-      const on_rtt_results_callback& on_results_callback);
-  wifi_error cancelRttRangeRequest(
-      wifi_request_id id, const std::vector<std::array<uint8_t, 6>>& mac_addrs);
-  std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities();
-  std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo();
-  wifi_error enableRttResponder(wifi_request_id id,
-                                const wifi_channel_info& channel_hint,
-                                uint32_t max_duration_secs,
-                                const wifi_rtt_responder& info);
-  wifi_error disableRttResponder(wifi_request_id id);
-  wifi_error setRttLci(wifi_request_id id, const wifi_lci_information& info);
-  wifi_error setRttLcr(wifi_request_id id, const wifi_lcr_information& info);
-  // NAN functions.
-  wifi_error nanRegisterCallbackHandlers(const NanCallbackHandlers& callbacks);
-  wifi_error nanEnableRequest(transaction_id id, const NanEnableRequest& msg);
-  wifi_error nanDisableRequest(transaction_id id);
-  wifi_error nanPublishRequest(transaction_id id, const NanPublishRequest& msg);
-  wifi_error nanPublishCancelRequest(transaction_id id,
-                                     const NanPublishCancelRequest& msg);
-  wifi_error nanSubscribeRequest(transaction_id id,
-                                 const NanSubscribeRequest& msg);
-  wifi_error nanSubscribeCancelRequest(transaction_id id,
-                                       const NanSubscribeCancelRequest& msg);
-  wifi_error nanTransmitFollowupRequest(transaction_id id,
-                                        const NanTransmitFollowupRequest& msg);
-  wifi_error nanStatsRequest(transaction_id id, const NanStatsRequest& msg);
-  wifi_error nanConfigRequest(transaction_id id, const NanConfigRequest& msg);
-  wifi_error nanTcaRequest(transaction_id id, const NanTCARequest& msg);
-  wifi_error nanBeaconSdfPayloadRequest(transaction_id id,
-                                        const NanBeaconSdfPayloadRequest& msg);
-  std::pair<wifi_error, NanVersion> nanGetVersion();
-  wifi_error nanGetCapabilities(transaction_id id);
-  wifi_error nanDataInterfaceCreate(transaction_id id,
-                                    const std::string& iface_name);
-  wifi_error nanDataInterfaceDelete(transaction_id id,
-                                    const std::string& iface_name);
-  wifi_error nanDataRequestInitiator(transaction_id id,
-                                     const NanDataPathInitiatorRequest& msg);
-  wifi_error nanDataIndicationResponse(
-      transaction_id id, const NanDataPathIndicationResponse& msg);
-  wifi_error nanDataEnd(transaction_id id, uint32_t ndpInstanceId);
-  // AP functions.
-  wifi_error setCountryCode(std::array<int8_t, 2> code);
-
- private:
-  // Retrieve the interface handle to be used for the "wlan" interface.
-  wifi_error retrieveWlanInterfaceHandle();
-  // Run the legacy HAL event loop thread.
-  void runEventLoop();
-  // Retrieve the cached gscan results to pass the results back to the external
-  // callbacks.
-  std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
-  getGscanCachedResults();
-  void invalidate();
-
-  // Global function table of legacy HAL.
-  wifi_hal_fn global_func_table_;
-  // Opaque handle to be used for all global operations.
-  wifi_handle global_handle_;
-  // Opaque handle to be used for all wlan0 interface specific operations.
-  wifi_interface_handle wlan_interface_handle_;
-  // Flag to indicate if we have initiated the cleanup of legacy HAL.
-  std::atomic<bool> awaiting_event_loop_termination_;
-  std::condition_variable_any stop_wait_cv_;
-  // Flag to indicate if the legacy HAL has been started.
-  bool is_started_;
-  wifi_system::InterfaceTool iface_tool_;
-};
-
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.1/default/wifi_legacy_hal_stubs.cpp b/wifi/1.1/default/wifi_legacy_hal_stubs.cpp
deleted file mode 100644
index c02e3ba..0000000
--- a/wifi/1.1/default/wifi_legacy_hal_stubs.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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.
- */
-
-#include "wifi_legacy_hal_stubs.h"
-
-// TODO: Remove these stubs from HalTool in libwifi-system.
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace legacy_hal {
-template <typename>
-struct stubFunction;
-
-template <typename R, typename... Args>
-struct stubFunction<R (*)(Args...)> {
-  static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
-};
-template <typename... Args>
-struct stubFunction<void (*)(Args...)> {
-  static constexpr void invoke(Args...) {}
-};
-
-template <typename T>
-void populateStubFor(T* val) {
-  *val = &stubFunction<T>::invoke;
-}
-
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
-  if (hal_fn == nullptr) {
-    return false;
-  }
-  populateStubFor(&hal_fn->wifi_initialize);
-  populateStubFor(&hal_fn->wifi_cleanup);
-  populateStubFor(&hal_fn->wifi_event_loop);
-  populateStubFor(&hal_fn->wifi_get_error_info);
-  populateStubFor(&hal_fn->wifi_get_supported_feature_set);
-  populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
-  populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
-  populateStubFor(&hal_fn->wifi_get_supported_channels);
-  populateStubFor(&hal_fn->wifi_is_epr_supported);
-  populateStubFor(&hal_fn->wifi_get_ifaces);
-  populateStubFor(&hal_fn->wifi_get_iface_name);
-  populateStubFor(&hal_fn->wifi_set_iface_event_handler);
-  populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
-  populateStubFor(&hal_fn->wifi_start_gscan);
-  populateStubFor(&hal_fn->wifi_stop_gscan);
-  populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
-  populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
-  populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
-  populateStubFor(&hal_fn->wifi_set_significant_change_handler);
-  populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
-  populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
-  populateStubFor(&hal_fn->wifi_set_link_stats);
-  populateStubFor(&hal_fn->wifi_get_link_stats);
-  populateStubFor(&hal_fn->wifi_clear_link_stats);
-  populateStubFor(&hal_fn->wifi_get_valid_channels);
-  populateStubFor(&hal_fn->wifi_rtt_range_request);
-  populateStubFor(&hal_fn->wifi_rtt_range_cancel);
-  populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
-  populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
-  populateStubFor(&hal_fn->wifi_enable_responder);
-  populateStubFor(&hal_fn->wifi_disable_responder);
-  populateStubFor(&hal_fn->wifi_set_nodfs_flag);
-  populateStubFor(&hal_fn->wifi_start_logging);
-  populateStubFor(&hal_fn->wifi_set_epno_list);
-  populateStubFor(&hal_fn->wifi_reset_epno_list);
-  populateStubFor(&hal_fn->wifi_set_country_code);
-  populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
-  populateStubFor(&hal_fn->wifi_set_log_handler);
-  populateStubFor(&hal_fn->wifi_reset_log_handler);
-  populateStubFor(&hal_fn->wifi_set_alert_handler);
-  populateStubFor(&hal_fn->wifi_reset_alert_handler);
-  populateStubFor(&hal_fn->wifi_get_firmware_version);
-  populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
-  populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
-  populateStubFor(&hal_fn->wifi_get_ring_data);
-  populateStubFor(&hal_fn->wifi_enable_tdls);
-  populateStubFor(&hal_fn->wifi_disable_tdls);
-  populateStubFor(&hal_fn->wifi_get_tdls_status);
-  populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
-  populateStubFor(&hal_fn->wifi_get_driver_version);
-  populateStubFor(&hal_fn->wifi_set_passpoint_list);
-  populateStubFor(&hal_fn->wifi_reset_passpoint_list);
-  populateStubFor(&hal_fn->wifi_set_lci);
-  populateStubFor(&hal_fn->wifi_set_lcr);
-  populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
-  populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
-  populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
-  populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
-  populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
-  populateStubFor(&hal_fn->wifi_configure_nd_offload);
-  populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
-  populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
-  populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
-  populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
-  populateStubFor(&hal_fn->wifi_nan_enable_request);
-  populateStubFor(&hal_fn->wifi_nan_disable_request);
-  populateStubFor(&hal_fn->wifi_nan_publish_request);
-  populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
-  populateStubFor(&hal_fn->wifi_nan_subscribe_request);
-  populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
-  populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
-  populateStubFor(&hal_fn->wifi_nan_stats_request);
-  populateStubFor(&hal_fn->wifi_nan_config_request);
-  populateStubFor(&hal_fn->wifi_nan_tca_request);
-  populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
-  populateStubFor(&hal_fn->wifi_nan_register_handler);
-  populateStubFor(&hal_fn->wifi_nan_get_version);
-  populateStubFor(&hal_fn->wifi_nan_get_capabilities);
-  populateStubFor(&hal_fn->wifi_nan_data_interface_create);
-  populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
-  populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
-  populateStubFor(&hal_fn->wifi_nan_data_indication_response);
-  populateStubFor(&hal_fn->wifi_nan_data_end);
-  populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
-  populateStubFor(&hal_fn->wifi_set_packet_filter);
-  populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
-  populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
-  populateStubFor(&hal_fn->wifi_configure_roaming);
-  populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
-  populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
-  return true;
-}
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi_legacy_hal_stubs.h b/wifi/1.1/default/wifi_legacy_hal_stubs.h
deleted file mode 100644
index bfc4c9b..0000000
--- a/wifi/1.1/default/wifi_legacy_hal_stubs.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 WIFI_LEGACY_HAL_STUBS_H_
-#define WIFI_LEGACY_HAL_STUBS_H_
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace legacy_hal {
-#include <hardware_legacy/wifi_hal.h>
-
-bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
-}  // namespace legacy_hal
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/1.1/default/wifi_mode_controller.cpp b/wifi/1.1/default/wifi_mode_controller.cpp
deleted file mode 100644
index b8a44c2..0000000
--- a/wifi/1.1/default/wifi_mode_controller.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-
-#include "wifi_mode_controller.h"
-
-using android::hardware::wifi::V1_0::IfaceType;
-using android::wifi_hal::DriverTool;
-
-namespace {
-int convertIfaceTypeToFirmwareMode(IfaceType type) {
-  int mode;
-  switch (type) {
-    case IfaceType::AP:
-      mode = DriverTool::kFirmwareModeAp;
-      break;
-    case IfaceType::P2P:
-      mode = DriverTool::kFirmwareModeP2p;
-      break;
-    case IfaceType::NAN:
-      // NAN is exposed in STA mode currently.
-      mode = DriverTool::kFirmwareModeSta;
-      break;
-    case IfaceType::STA:
-      mode = DriverTool::kFirmwareModeSta;
-      break;
-  }
-  return mode;
-}
-}
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace mode_controller {
-
-WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
-
-bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
-  return driver_tool_->IsFirmwareModeChangeNeeded(
-      convertIfaceTypeToFirmwareMode(type));
-}
-
-bool WifiModeController::changeFirmwareMode(IfaceType type) {
-  if (!driver_tool_->LoadDriver()) {
-    LOG(ERROR) << "Failed to load WiFi driver";
-    return false;
-  }
-  if (!driver_tool_->ChangeFirmwareMode(convertIfaceTypeToFirmwareMode(type))) {
-    LOG(ERROR) << "Failed to change firmware mode";
-    return false;
-  }
-  return true;
-}
-
-bool WifiModeController::deinitialize() {
-  if (!driver_tool_->UnloadDriver()) {
-    LOG(ERROR) << "Failed to unload WiFi driver";
-    return false;
-  }
-  return true;
-}
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi_mode_controller.h b/wifi/1.1/default/wifi_mode_controller.h
deleted file mode 100644
index 6984509..0000000
--- a/wifi/1.1/default/wifi_mode_controller.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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 WIFI_MODE_CONTROLLER_H_
-#define WIFI_MODE_CONTROLLER_H_
-
-#include <wifi_hal/driver_tool.h>
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-namespace mode_controller {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * Class that encapsulates all firmware mode configuration.
- * This class will perform the necessary firmware reloads to put the chip in the
- * required state (essentially a wrapper over DriverTool).
- */
-class WifiModeController {
- public:
-  WifiModeController();
-
-  // Checks if a firmware mode change is necessary to support the specified
-  // iface type operations.
-  bool isFirmwareModeChangeNeeded(IfaceType type);
-  // Change the firmware mode to support the specified iface type operations.
-  bool changeFirmwareMode(IfaceType type);
-  // Unload the driver. This should be invoked whenever |IWifi.stop()| is
-  // invoked.
-  bool deinitialize();
-
- private:
-  std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
-};
-
-}  // namespace mode_controller
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.1/default/wifi_nan_iface.cpp b/wifi/1.1/default/wifi_nan_iface.cpp
deleted file mode 100644
index a111d06..0000000
--- a/wifi/1.1/default/wifi_nan_iface.cpp
+++ /dev/null
@@ -1,769 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_nan_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiNanIface::WifiNanIface(
-    const std::string& ifname,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {
-  // Register all the callbacks here. these should be valid for the lifetime
-  // of the object. Whenever the mode changes legacy HAL will remove
-  // all of these callbacks.
-  legacy_hal::NanCallbackHandlers callback_handlers;
-  android::wp<WifiNanIface> weak_ptr_this(this);
-
-  // Callback for response.
-  callback_handlers.on_notify_response = [weak_ptr_this](
-      legacy_hal::transaction_id id, const legacy_hal::NanResponseMsg& msg) {
-    const auto shared_ptr_this = weak_ptr_this.promote();
-    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-      LOG(ERROR) << "Callback invoked on an invalid object";
-      return;
-    }
-    WifiNanStatus wifiNanStatus;
-    if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(msg,
-                                                                &wifiNanStatus)) {
-      LOG(ERROR) << "Failed to convert nan response header";
-      return;
-    }
-
-    switch (msg.response_type) {
-    case legacy_hal::NAN_RESPONSE_ENABLED: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyEnableResponse(id, wifiNanStatus).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_RESPONSE_DISABLED: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyDisableResponse(id, wifiNanStatus).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_RESPONSE_PUBLISH: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyStartPublishResponse(id, wifiNanStatus,
-                        msg.body.publish_response.publish_id).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyStopPublishResponse(id, wifiNanStatus).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyTransmitFollowupResponse(id, wifiNanStatus).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyStartSubscribeResponse(id, wifiNanStatus,
-                        msg.body.subscribe_response.subscribe_id).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyStopSubscribeResponse(id, wifiNanStatus).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_RESPONSE_CONFIG: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyConfigResponse(id, wifiNanStatus).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-     }
-    case legacy_hal::NAN_GET_CAPABILITIES: {
-        NanCapabilities hidl_struct;
-        if (!hidl_struct_util::convertLegacyNanCapabilitiesResponseToHidl(
-                msg.body.nan_capabilities, &hidl_struct)) {
-            LOG(ERROR) << "Failed to convert nan capabilities response";
-            return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyCapabilitiesResponse(id, wifiNanStatus,
-                                                    hidl_struct).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_DP_INTERFACE_CREATE: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyCreateDataInterfaceResponse(id, wifiNanStatus).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_DP_INTERFACE_DELETE: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyDeleteDataInterfaceResponse(id, wifiNanStatus).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyInitiateDataPathResponse(id, wifiNanStatus,
-                msg.body.data_request_response.ndp_instance_id).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyRespondToDataPathIndicationResponse(id, wifiNanStatus).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_DP_END: {
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->notifyTerminateDataPathResponse(id, wifiNanStatus).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-          }
-        }
-        break;
-    }
-    case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
-        /* fall through */
-    case legacy_hal::NAN_RESPONSE_TCA:
-        /* fall through */
-    case legacy_hal::NAN_RESPONSE_STATS:
-        /* fall through */
-    case legacy_hal::NAN_RESPONSE_ERROR:
-        /* fall through */
-    default:
-        LOG(ERROR) << "Unknown or unhandled response type: " << msg.response_type;
-        return;
-    }
-  };
-
-  callback_handlers.on_event_disc_eng_event = [weak_ptr_this](
-        const legacy_hal::NanDiscEngEventInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      NanClusterEventInd hidl_struct;
-      // event types defined identically - hence can be cast
-      hidl_struct.eventType = (NanClusterEventType) msg.event_type;
-      hidl_struct.addr = msg.data.mac_addr.addr;
-
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->eventClusterEvent(hidl_struct).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-        }
-      }
-  };
-
-  callback_handlers.on_event_disabled = [weak_ptr_this](
-        const legacy_hal::NanDisabledInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      WifiNanStatus status;
-      hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason, sizeof(msg.nan_reason),
-            &status);
-
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->eventDisabled(status).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-        }
-      }
-  };
-
-  callback_handlers.on_event_publish_terminated = [weak_ptr_this](
-        const legacy_hal::NanPublishTerminatedInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      WifiNanStatus status;
-      hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason, sizeof(msg.nan_reason),
-            &status);
-
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->eventPublishTerminated(msg.publish_id, status).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-        }
-      }
-  };
-
-  callback_handlers.on_event_subscribe_terminated = [weak_ptr_this](
-        const legacy_hal::NanSubscribeTerminatedInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      WifiNanStatus status;
-      hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason, sizeof(msg.nan_reason),
-            &status);
-
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->eventSubscribeTerminated(msg.subscribe_id, status).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-        }
-      }
-  };
-
-  callback_handlers.on_event_match = [weak_ptr_this](
-        const legacy_hal::NanMatchInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      NanMatchInd hidl_struct;
-      if (!hidl_struct_util::convertLegacyNanMatchIndToHidl(
-            msg, &hidl_struct)) {
-          LOG(ERROR) << "Failed to convert nan capabilities response";
-          return;
-      }
-
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->eventMatch(hidl_struct).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-        }
-      }
-  };
-
-  callback_handlers.on_event_match_expired = [weak_ptr_this](
-        const legacy_hal::NanMatchExpiredInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->eventMatchExpired(msg.publish_subscribe_id,
-                msg.requestor_instance_id).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-        }
-      }
-  };
-
-  callback_handlers.on_event_followup = [weak_ptr_this](
-        const legacy_hal::NanFollowupInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      NanFollowupReceivedInd hidl_struct;
-      if (!hidl_struct_util::convertLegacyNanFollowupIndToHidl(
-            msg, &hidl_struct)) {
-          LOG(ERROR) << "Failed to convert nan capabilities response";
-          return;
-      }
-
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->eventFollowupReceived(hidl_struct).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-        }
-      }
-  };
-
-  callback_handlers.on_event_transmit_follow_up = [weak_ptr_this](
-        const legacy_hal::NanTransmitFollowupInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      WifiNanStatus status;
-      hidl_struct_util::convertToWifiNanStatus(msg.reason, msg.nan_reason, sizeof(msg.nan_reason),
-            &status);
-
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-        }
-      }
-  };
-
-  callback_handlers.on_event_data_path_request = [weak_ptr_this](
-        const legacy_hal::NanDataPathRequestInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      NanDataPathRequestInd hidl_struct;
-      if (!hidl_struct_util::convertLegacyNanDataPathRequestIndToHidl(
-            msg, &hidl_struct)) {
-          LOG(ERROR) << "Failed to convert nan capabilities response";
-          return;
-      }
-
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->eventDataPathRequest(hidl_struct).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-        }
-      }
-  };
-
-  callback_handlers.on_event_data_path_confirm = [weak_ptr_this](
-        const legacy_hal::NanDataPathConfirmInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      NanDataPathConfirmInd hidl_struct;
-      if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(
-            msg, &hidl_struct)) {
-          LOG(ERROR) << "Failed to convert nan capabilities response";
-          return;
-      }
-
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        if (!callback->eventDataPathConfirm(hidl_struct).isOk()) {
-            LOG(ERROR) << "Failed to invoke the callback";
-        }
-      }
-  };
-
-  callback_handlers.on_event_data_path_end = [weak_ptr_this](
-        const legacy_hal::NanDataPathEndInd& msg) {
-      const auto shared_ptr_this = weak_ptr_this.promote();
-      if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-        LOG(ERROR) << "Callback invoked on an invalid object";
-        return;
-      }
-      for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-        for (int i = 0; i < msg.num_ndp_instances; ++i) {
-            if (!callback->eventDataPathTerminated(msg.ndp_instance_id[i]).isOk()) {
-                LOG(ERROR) << "Failed to invoke the callback";
-            }
-        }
-      }
-  };
-
-  callback_handlers.on_event_beacon_sdf_payload = [weak_ptr_this](
-        const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
-      LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
-  };
-
-  callback_handlers.on_event_range_request = [weak_ptr_this](
-        const legacy_hal::NanRangeRequestInd& /* msg */) {
-      LOG(ERROR) << "on_event_range_request - should not be called";
-  };
-
-  callback_handlers.on_event_range_report = [weak_ptr_this](
-        const legacy_hal::NanRangeReportInd& /* msg */) {
-      LOG(ERROR) << "on_event_range_report - should not be called";
-  };
-
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanRegisterCallbackHandlers(callback_handlers);
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
-    invalidate();
-  }
-}
-
-void WifiNanIface::invalidate() {
-  // send commands to HAL to actually disable and destroy interfaces
-  legacy_hal_.lock()->nanDisableRequest(0xFFFF);
-  legacy_hal_.lock()->nanDataInterfaceDelete(0xFFFE, "aware_data0");
-  legacy_hal_.lock()->nanDataInterfaceDelete(0xFFFD, "aware_data1");
-
-  legacy_hal_.reset();
-  event_cb_handler_.invalidate();
-  is_valid_ = false;
-}
-
-bool WifiNanIface::isValid() {
-  return is_valid_;
-}
-
-std::set<sp<IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks() {
-  return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::getNameInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiNanIface::getType(getType_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::getTypeInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiNanIface::registerEventCallback(
-    const sp<IWifiNanIfaceEventCallback>& callback,
-    registerEventCallback_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::registerEventCallbackInternal,
-                         hidl_status_cb,
-                         callback);
-}
-
-Return<void> WifiNanIface::getCapabilitiesRequest(uint16_t cmd_id,
-                                                  getCapabilitiesRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::getCapabilitiesRequestInternal,
-                         hidl_status_cb,
-                         cmd_id);
-}
-
-Return<void> WifiNanIface::enableRequest(uint16_t cmd_id,
-                                         const NanEnableRequest& msg,
-                                         enableRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::enableRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         msg);
-}
-
-Return<void> WifiNanIface::configRequest(uint16_t cmd_id,
-                                         const NanConfigRequest& msg,
-                                         configRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::configRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         msg);
-}
-
-Return<void> WifiNanIface::disableRequest(uint16_t cmd_id,
-                                          disableRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::disableRequestInternal,
-                         hidl_status_cb,
-                         cmd_id);
-}
-
-Return<void> WifiNanIface::startPublishRequest(uint16_t cmd_id,
-                                               const NanPublishRequest& msg,
-                                               startPublishRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::startPublishRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         msg);
-}
-
-Return<void> WifiNanIface::stopPublishRequest(
-    uint16_t cmd_id,
-    uint8_t sessionId,
-    stopPublishRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::stopPublishRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         sessionId);
-}
-
-Return<void> WifiNanIface::startSubscribeRequest(
-    uint16_t cmd_id,
-    const NanSubscribeRequest& msg,
-    startSubscribeRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::startSubscribeRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         msg);
-}
-
-Return<void> WifiNanIface::stopSubscribeRequest(
-    uint16_t cmd_id,
-    uint8_t sessionId,
-    stopSubscribeRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::stopSubscribeRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         sessionId);
-}
-
-Return<void> WifiNanIface::transmitFollowupRequest(
-    uint16_t cmd_id,
-    const NanTransmitFollowupRequest& msg,
-    transmitFollowupRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::transmitFollowupRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         msg);
-}
-
-Return<void> WifiNanIface::createDataInterfaceRequest(
-    uint16_t cmd_id,
-    const hidl_string& iface_name,
-    createDataInterfaceRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::createDataInterfaceRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         iface_name);
-}
-
-Return<void> WifiNanIface::deleteDataInterfaceRequest(
-    uint16_t cmd_id,
-    const hidl_string& iface_name,
-    deleteDataInterfaceRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::deleteDataInterfaceRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         iface_name);
-}
-
-Return<void> WifiNanIface::initiateDataPathRequest(
-    uint16_t cmd_id,
-    const NanInitiateDataPathRequest& msg,
-    initiateDataPathRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::initiateDataPathRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         msg);
-}
-
-Return<void> WifiNanIface::respondToDataPathIndicationRequest(
-    uint16_t cmd_id,
-    const NanRespondToDataPathIndicationRequest& msg,
-    respondToDataPathIndicationRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::respondToDataPathIndicationRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         msg);
-}
-
-Return<void> WifiNanIface::terminateDataPathRequest(uint16_t cmd_id, uint32_t ndpInstanceId,
-    terminateDataPathRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiNanIface::terminateDataPathRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         ndpInstanceId);
-}
-
-std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
-  return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiNanIface::getTypeInternal() {
-  return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
-}
-
-WifiStatus WifiNanIface::registerEventCallbackInternal(
-    const sp<IWifiNanIfaceEventCallback>& callback) {
-  if (!event_cb_handler_.addCallback(callback)) {
-    return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t cmd_id) {
-  legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanGetCapabilities(cmd_id);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::enableRequestInternal(uint16_t cmd_id,
-                                               const NanEnableRequest& msg) {
-  legacy_hal::NanEnableRequest legacy_msg;
-  if (!hidl_struct_util::convertHidlNanEnableRequestToLegacy(msg, &legacy_msg)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanEnableRequest(cmd_id, legacy_msg);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::configRequestInternal(
-    uint16_t cmd_id, const NanConfigRequest& msg) {
-  legacy_hal::NanConfigRequest legacy_msg;
-  if (!hidl_struct_util::convertHidlNanConfigRequestToLegacy(msg,
-                                                             &legacy_msg)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanConfigRequest(cmd_id, legacy_msg);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanDisableRequest(cmd_id);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::startPublishRequestInternal(uint16_t cmd_id,
-                                                     const NanPublishRequest& msg) {
-  legacy_hal::NanPublishRequest legacy_msg;
-  if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(msg,
-                                                              &legacy_msg)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanPublishRequest(cmd_id, legacy_msg);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::stopPublishRequestInternal(
-    uint16_t cmd_id, uint8_t sessionId) {
-  legacy_hal::NanPublishCancelRequest legacy_msg;
-  legacy_msg.publish_id = sessionId;
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanPublishCancelRequest(cmd_id, legacy_msg);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::startSubscribeRequestInternal(
-    uint16_t cmd_id, const NanSubscribeRequest& msg) {
-  legacy_hal::NanSubscribeRequest legacy_msg;
-  if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(msg,
-                                                                &legacy_msg)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanSubscribeRequest(cmd_id, legacy_msg);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::stopSubscribeRequestInternal(
-    uint16_t cmd_id, uint8_t sessionId) {
-  legacy_hal::NanSubscribeCancelRequest legacy_msg;
-  legacy_msg.subscribe_id = sessionId;
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanSubscribeCancelRequest(cmd_id, legacy_msg);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::transmitFollowupRequestInternal(
-    uint16_t cmd_id, const NanTransmitFollowupRequest& msg) {
-  legacy_hal::NanTransmitFollowupRequest legacy_msg;
-  if (!hidl_struct_util::convertHidlNanTransmitFollowupRequestToLegacy(msg, &legacy_msg)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanTransmitFollowupRequest(cmd_id, legacy_msg);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiNanIface::createDataInterfaceRequestInternal(
-    uint16_t cmd_id, const std::string& iface_name) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanDataInterfaceCreate(cmd_id, iface_name);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::deleteDataInterfaceRequestInternal(
-    uint16_t cmd_id, const std::string& iface_name) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanDataInterfaceDelete(cmd_id, iface_name);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::initiateDataPathRequestInternal(
-    uint16_t cmd_id, const NanInitiateDataPathRequest& msg) {
-  legacy_hal::NanDataPathInitiatorRequest legacy_msg;
-  if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequestToLegacy(msg, &legacy_msg)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanDataRequestInitiator(cmd_id, legacy_msg);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
-    uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg) {
-  legacy_hal::NanDataPathIndicationResponse legacy_msg;
-  if (!hidl_struct_util::convertHidlNanDataPathIndicationResponseToLegacy(msg, &legacy_msg)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanDataIndicationResponse(cmd_id, legacy_msg);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-WifiStatus WifiNanIface::terminateDataPathRequestInternal(
-    uint16_t cmd_id, uint32_t ndpInstanceId) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanDataEnd(cmd_id, ndpInstanceId);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi_nan_iface.h b/wifi/1.1/default/wifi_nan_iface.h
deleted file mode 100644
index 260d8ab..0000000
--- a/wifi/1.1/default/wifi_nan_iface.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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 WIFI_NAN_IFACE_H_
-#define WIFI_NAN_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiNanIface.h>
-#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a NAN Iface instance.
- */
-class WifiNanIface : public V1_0::IWifiNanIface {
- public:
-  WifiNanIface(const std::string& ifname,
-               const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-  // Refer to |WifiChip::invalidate()|.
-  void invalidate();
-  bool isValid();
-
-  // HIDL methods exposed.
-  Return<void> getName(getName_cb hidl_status_cb) override;
-  Return<void> getType(getType_cb hidl_status_cb) override;
-  Return<void> registerEventCallback(
-      const sp<IWifiNanIfaceEventCallback>& callback,
-      registerEventCallback_cb hidl_status_cb) override;
-  Return<void> getCapabilitiesRequest(uint16_t cmd_id,
-                                      getCapabilitiesRequest_cb hidl_status_cb) override;
-  Return<void> enableRequest(uint16_t cmd_id,
-                             const NanEnableRequest& msg,
-                             enableRequest_cb hidl_status_cb) override;
-  Return<void> configRequest(uint16_t cmd_id,
-                             const NanConfigRequest& msg,
-                             configRequest_cb hidl_status_cb) override;
-  Return<void> disableRequest(uint16_t cmd_id,
-                              disableRequest_cb hidl_status_cb) override;
-  Return<void> startPublishRequest(uint16_t cmd_id,
-                                   const NanPublishRequest& msg,
-                                   startPublishRequest_cb hidl_status_cb) override;
-  Return<void> stopPublishRequest(uint16_t cmd_id,
-                                  uint8_t sessionId,
-                                  stopPublishRequest_cb hidl_status_cb) override;
-  Return<void> startSubscribeRequest(uint16_t cmd_id,
-                                     const NanSubscribeRequest& msg,
-                                    startSubscribeRequest_cb hidl_status_cb) override;
-  Return<void> stopSubscribeRequest(uint16_t cmd_id,
-                                    uint8_t sessionId,
-                                    stopSubscribeRequest_cb hidl_status_cb) override;
-  Return<void> transmitFollowupRequest(uint16_t cmd_id,
-                                       const NanTransmitFollowupRequest& msg,
-                                       transmitFollowupRequest_cb hidl_status_cb) override;
-  Return<void> createDataInterfaceRequest(uint16_t cmd_id,
-                                          const hidl_string& iface_name,
-                                          createDataInterfaceRequest_cb hidl_status_cb) override;
-  Return<void> deleteDataInterfaceRequest(uint16_t cmd_id,
-                                          const hidl_string& iface_name,
-                                          deleteDataInterfaceRequest_cb hidl_status_cb) override;
-  Return<void> initiateDataPathRequest(uint16_t cmd_id,
-                                       const NanInitiateDataPathRequest& msg,
-                                       initiateDataPathRequest_cb hidl_status_cb) override;
-  Return<void> respondToDataPathIndicationRequest(
-      uint16_t cmd_id,
-      const NanRespondToDataPathIndicationRequest& msg,
-      respondToDataPathIndicationRequest_cb hidl_status_cb) override;
-  Return<void> terminateDataPathRequest(uint16_t cmd_id,
-                                        uint32_t ndpInstanceId,
-                                        terminateDataPathRequest_cb hidl_status_cb) override;
-
- private:
-  // Corresponding worker functions for the HIDL methods.
-  std::pair<WifiStatus, std::string> getNameInternal();
-  std::pair<WifiStatus, IfaceType> getTypeInternal();
-  WifiStatus registerEventCallbackInternal(
-      const sp<IWifiNanIfaceEventCallback>& callback);
-  WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
-  WifiStatus enableRequestInternal(uint16_t cmd_id,
-                                   const NanEnableRequest& msg);
-  WifiStatus configRequestInternal(uint16_t cmd_id,
-                                   const NanConfigRequest& msg);
-  WifiStatus disableRequestInternal(uint16_t cmd_id);
-  WifiStatus startPublishRequestInternal(uint16_t cmd_id,
-                                         const NanPublishRequest& msg);
-  WifiStatus stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId);
-  WifiStatus startSubscribeRequestInternal(uint16_t cmd_id,
-                                           const NanSubscribeRequest& msg);
-  WifiStatus stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId);
-  WifiStatus transmitFollowupRequestInternal(
-      uint16_t cmd_id, const NanTransmitFollowupRequest& msg);
-  WifiStatus createDataInterfaceRequestInternal(uint16_t cmd_id,
-                                                const std::string& iface_name);
-  WifiStatus deleteDataInterfaceRequestInternal(uint16_t cmd_id,
-                                                const std::string& iface_name);
-  WifiStatus initiateDataPathRequestInternal(
-      uint16_t cmd_id, const NanInitiateDataPathRequest& msg);
-  WifiStatus respondToDataPathIndicationRequestInternal(
-      uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg);
-  WifiStatus terminateDataPathRequestInternal(
-      uint16_t cmd_id, uint32_t ndpInstanceId);
-
-  std::set<sp<IWifiNanIfaceEventCallback>> getEventCallbacks();
-
-  std::string ifname_;
-  std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-  bool is_valid_;
-  hidl_callback_util::HidlCallbackHandler<IWifiNanIfaceEventCallback>
-      event_cb_handler_;
-
-  DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_NAN_IFACE_H_
diff --git a/wifi/1.1/default/wifi_p2p_iface.cpp b/wifi/1.1/default/wifi_p2p_iface.cpp
deleted file mode 100644
index 78e08db..0000000
--- a/wifi/1.1/default/wifi_p2p_iface.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "wifi_p2p_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiP2pIface::WifiP2pIface(
-    const std::string& ifname,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
-
-void WifiP2pIface::invalidate() {
-  legacy_hal_.reset();
-  is_valid_ = false;
-}
-
-bool WifiP2pIface::isValid() {
-  return is_valid_;
-}
-
-Return<void> WifiP2pIface::getName(getName_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiP2pIface::getNameInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiP2pIface::getType(getType_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiP2pIface::getTypeInternal,
-                         hidl_status_cb);
-}
-
-std::pair<WifiStatus, std::string> WifiP2pIface::getNameInternal() {
-  return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() {
-  return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::P2P};
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi_p2p_iface.h b/wifi/1.1/default/wifi_p2p_iface.h
deleted file mode 100644
index f563a3d..0000000
--- a/wifi/1.1/default/wifi_p2p_iface.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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 WIFI_P2P_IFACE_H_
-#define WIFI_P2P_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a P2P Iface instance.
- */
-class WifiP2pIface : public V1_0::IWifiP2pIface {
- public:
-  WifiP2pIface(const std::string& ifname,
-               const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-  // Refer to |WifiChip::invalidate()|.
-  void invalidate();
-  bool isValid();
-
-  // HIDL methods exposed.
-  Return<void> getName(getName_cb hidl_status_cb) override;
-  Return<void> getType(getType_cb hidl_status_cb) override;
-
- private:
-  // Corresponding worker functions for the HIDL methods.
-  std::pair<WifiStatus, std::string> getNameInternal();
-  std::pair<WifiStatus, IfaceType> getTypeInternal();
-
-  std::string ifname_;
-  std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-  bool is_valid_;
-
-  DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_P2P_IFACE_H_
diff --git a/wifi/1.1/default/wifi_rtt_controller.cpp b/wifi/1.1/default/wifi_rtt_controller.cpp
deleted file mode 100644
index 9ef702d..0000000
--- a/wifi/1.1/default/wifi_rtt_controller.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_rtt_controller.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiRttController::WifiRttController(
-    const sp<IWifiIface>& bound_iface,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : bound_iface_(bound_iface), legacy_hal_(legacy_hal), is_valid_(true) {}
-
-void WifiRttController::invalidate() {
-  legacy_hal_.reset();
-  event_callbacks_.clear();
-  is_valid_ = false;
-}
-
-bool WifiRttController::isValid() {
-  return is_valid_;
-}
-
-std::vector<sp<IWifiRttControllerEventCallback>>
-WifiRttController::getEventCallbacks() {
-  return event_callbacks_;
-}
-
-Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::getBoundIfaceInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiRttController::registerEventCallback(
-    const sp<IWifiRttControllerEventCallback>& callback,
-    registerEventCallback_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::registerEventCallbackInternal,
-                         hidl_status_cb,
-                         callback);
-}
-
-Return<void> WifiRttController::rangeRequest(
-    uint32_t cmd_id,
-    const hidl_vec<RttConfig>& rtt_configs,
-    rangeRequest_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::rangeRequestInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         rtt_configs);
-}
-
-Return<void> WifiRttController::rangeCancel(
-    uint32_t cmd_id,
-    const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
-    rangeCancel_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::rangeCancelInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         addrs);
-}
-
-Return<void> WifiRttController::getCapabilities(
-    getCapabilities_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::getCapabilitiesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiRttController::setLci(uint32_t cmd_id,
-                                       const RttLciInformation& lci,
-                                       setLci_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::setLciInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         lci);
-}
-
-Return<void> WifiRttController::setLcr(uint32_t cmd_id,
-                                       const RttLcrInformation& lcr,
-                                       setLcr_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::setLcrInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         lcr);
-}
-
-Return<void> WifiRttController::getResponderInfo(
-    getResponderInfo_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::getResponderInfoInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiRttController::enableResponder(
-    uint32_t cmd_id,
-    const WifiChannelInfo& channel_hint,
-    uint32_t max_duration_seconds,
-    const RttResponder& info,
-    enableResponder_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::enableResponderInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         channel_hint,
-                         max_duration_seconds,
-                         info);
-}
-
-Return<void> WifiRttController::disableResponder(
-    uint32_t cmd_id, disableResponder_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
-                         &WifiRttController::disableResponderInternal,
-                         hidl_status_cb,
-                         cmd_id);
-}
-
-std::pair<WifiStatus, sp<IWifiIface>>
-WifiRttController::getBoundIfaceInternal() {
-  return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
-}
-
-WifiStatus WifiRttController::registerEventCallbackInternal(
-    const sp<IWifiRttControllerEventCallback>& callback) {
-  // TODO(b/31632518): remove the callback when the client is destroyed
-  event_callbacks_.emplace_back(callback);
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-WifiStatus WifiRttController::rangeRequestInternal(
-    uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
-  std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
-  if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(
-          rtt_configs, &legacy_configs)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  android::wp<WifiRttController> weak_ptr_this(this);
-  const auto& on_results_callback = [weak_ptr_this](
-      legacy_hal::wifi_request_id id,
-      const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
-    const auto shared_ptr_this = weak_ptr_this.promote();
-    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-      LOG(ERROR) << "Callback invoked on an invalid object";
-      return;
-    }
-    std::vector<RttResult> hidl_results;
-    if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(
-            results, &hidl_results)) {
-      LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
-      return;
-    }
-    for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-      callback->onResults(id, hidl_results);
-    }
-  };
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->startRttRangeRequest(
-          cmd_id, legacy_configs, on_results_callback);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::rangeCancelInternal(
-    uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
-  std::vector<std::array<uint8_t, 6>> legacy_addrs;
-  for (const auto& addr : addrs) {
-    legacy_addrs.push_back(addr);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->cancelRttRangeRequest(cmd_id, legacy_addrs);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, RttCapabilities>
-WifiRttController::getCapabilitiesInternal() {
-  legacy_hal::wifi_error legacy_status;
-  legacy_hal::wifi_rtt_capabilities legacy_caps;
-  std::tie(legacy_status, legacy_caps) =
-      legacy_hal_.lock()->getRttCapabilities();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  RttCapabilities hidl_caps;
-  if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps,
-                                                            &hidl_caps)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id,
-                                             const RttLciInformation& lci) {
-  legacy_hal::wifi_lci_information legacy_lci;
-  if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci,
-                                                              &legacy_lci)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->setRttLci(cmd_id, legacy_lci);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id,
-                                             const RttLcrInformation& lcr) {
-  legacy_hal::wifi_lcr_information legacy_lcr;
-  if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr,
-                                                              &legacy_lcr)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->setRttLcr(cmd_id, legacy_lcr);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, RttResponder>
-WifiRttController::getResponderInfoInternal() {
-  legacy_hal::wifi_error legacy_status;
-  legacy_hal::wifi_rtt_responder legacy_responder;
-  std::tie(legacy_status, legacy_responder) =
-      legacy_hal_.lock()->getRttResponderInfo();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  RttResponder hidl_responder;
-  if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder,
-                                                         &hidl_responder)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
-}
-
-WifiStatus WifiRttController::enableResponderInternal(
-    uint32_t cmd_id,
-    const WifiChannelInfo& channel_hint,
-    uint32_t max_duration_seconds,
-    const RttResponder& info) {
-  legacy_hal::wifi_channel_info legacy_channel_info;
-  if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(
-          channel_hint, &legacy_channel_info)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_rtt_responder legacy_responder;
-  if (!hidl_struct_util::convertHidlRttResponderToLegacy(info,
-                                                         &legacy_responder)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->enableRttResponder(
-      cmd_id, legacy_channel_info, max_duration_seconds, legacy_responder);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->disableRttResponder(cmd_id);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi_rtt_controller.h b/wifi/1.1/default/wifi_rtt_controller.h
deleted file mode 100644
index 5437885..0000000
--- a/wifi/1.1/default/wifi_rtt_controller.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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 WIFI_RTT_CONTROLLER_H_
-#define WIFI_RTT_CONTROLLER_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiIface.h>
-#include <android/hardware/wifi/1.0/IWifiRttController.h>
-#include <android/hardware/wifi/1.0/IWifiRttControllerEventCallback.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-
-/**
- * HIDL interface object used to control all RTT operations.
- */
-class WifiRttController : public V1_0::IWifiRttController {
- public:
-  WifiRttController(const sp<IWifiIface>& bound_iface,
-                    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-  // Refer to |WifiChip::invalidate()|.
-  void invalidate();
-  bool isValid();
-  std::vector<sp<IWifiRttControllerEventCallback>> getEventCallbacks();
-
-  // HIDL methods exposed.
-  Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
-  Return<void> registerEventCallback(
-      const sp<IWifiRttControllerEventCallback>& callback,
-      registerEventCallback_cb hidl_status_cb) override;
-  Return<void> rangeRequest(uint32_t cmd_id,
-                            const hidl_vec<RttConfig>& rtt_configs,
-                            rangeRequest_cb hidl_status_cb) override;
-  Return<void> rangeCancel(uint32_t cmd_id,
-                           const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
-                           rangeCancel_cb hidl_status_cb) override;
-  Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-  Return<void> setLci(uint32_t cmd_id,
-                      const RttLciInformation& lci,
-                      setLci_cb hidl_status_cb) override;
-  Return<void> setLcr(uint32_t cmd_id,
-                      const RttLcrInformation& lcr,
-                      setLcr_cb hidl_status_cb) override;
-  Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
-  Return<void> enableResponder(uint32_t cmd_id,
-                               const WifiChannelInfo& channel_hint,
-                               uint32_t max_duration_seconds,
-                               const RttResponder& info,
-                               enableResponder_cb hidl_status_cb) override;
-  Return<void> disableResponder(uint32_t cmd_id,
-                                disableResponder_cb hidl_status_cb) override;
-
- private:
-  // Corresponding worker functions for the HIDL methods.
-  std::pair<WifiStatus, sp<IWifiIface>> getBoundIfaceInternal();
-  WifiStatus registerEventCallbackInternal(
-      const sp<IWifiRttControllerEventCallback>& callback);
-  WifiStatus rangeRequestInternal(uint32_t cmd_id,
-                                  const std::vector<RttConfig>& rtt_configs);
-  WifiStatus rangeCancelInternal(
-      uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs);
-  std::pair<WifiStatus, RttCapabilities> getCapabilitiesInternal();
-  WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
-  WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
-  std::pair<WifiStatus, RttResponder> getResponderInfoInternal();
-  WifiStatus enableResponderInternal(uint32_t cmd_id,
-                                     const WifiChannelInfo& channel_hint,
-                                     uint32_t max_duration_seconds,
-                                     const RttResponder& info);
-  WifiStatus disableResponderInternal(uint32_t cmd_id);
-
-  sp<IWifiIface> bound_iface_;
-  std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-  std::vector<sp<IWifiRttControllerEventCallback>> event_callbacks_;
-  bool is_valid_;
-
-  DISALLOW_COPY_AND_ASSIGN(WifiRttController);
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/1.1/default/wifi_sta_iface.cpp b/wifi/1.1/default/wifi_sta_iface.cpp
deleted file mode 100644
index 28f3f02..0000000
--- a/wifi/1.1/default/wifi_sta_iface.cpp
+++ /dev/null
@@ -1,629 +0,0 @@
-/*
- * 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.
- */
-
-#include <android-base/logging.h>
-
-#include "hidl_return_util.h"
-#include "hidl_struct_util.h"
-#include "wifi_sta_iface.h"
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using hidl_return_util::validateAndCall;
-
-WifiStaIface::WifiStaIface(
-    const std::string& ifname,
-    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
-    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {
-  // Turn on DFS channel usage for STA iface.
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->setDfsFlag(true);
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    LOG(ERROR) << "Failed to set DFS flag; DFS channels may be unavailable.";
-  }
-}
-
-void WifiStaIface::invalidate() {
-  legacy_hal_.reset();
-  event_cb_handler_.invalidate();
-  is_valid_ = false;
-}
-
-bool WifiStaIface::isValid() {
-  return is_valid_;
-}
-
-std::set<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
-  return event_cb_handler_.getCallbacks();
-}
-
-Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::getNameInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getType(getType_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::getTypeInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiStaIface::registerEventCallback(
-    const sp<IWifiStaIfaceEventCallback>& callback,
-    registerEventCallback_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::registerEventCallbackInternal,
-                         hidl_status_cb,
-                         callback);
-}
-
-Return<void> WifiStaIface::getCapabilities(getCapabilities_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::getCapabilitiesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getApfPacketFilterCapabilities(
-    getApfPacketFilterCapabilities_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::getApfPacketFilterCapabilitiesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiStaIface::installApfPacketFilter(
-    uint32_t cmd_id,
-    const hidl_vec<uint8_t>& program,
-    installApfPacketFilter_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::installApfPacketFilterInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         program);
-}
-
-Return<void> WifiStaIface::getBackgroundScanCapabilities(
-    getBackgroundScanCapabilities_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::getBackgroundScanCapabilitiesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getValidFrequenciesForBand(
-    WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::getValidFrequenciesForBandInternal,
-                         hidl_status_cb,
-                         band);
-}
-
-Return<void> WifiStaIface::startBackgroundScan(
-    uint32_t cmd_id,
-    const StaBackgroundScanParameters& params,
-    startBackgroundScan_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::startBackgroundScanInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         params);
-}
-
-Return<void> WifiStaIface::stopBackgroundScan(
-    uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::stopBackgroundScanInternal,
-                         hidl_status_cb,
-                         cmd_id);
-}
-
-Return<void> WifiStaIface::enableLinkLayerStatsCollection(
-    bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::enableLinkLayerStatsCollectionInternal,
-                         hidl_status_cb,
-                         debug);
-}
-
-Return<void> WifiStaIface::disableLinkLayerStatsCollection(
-    disableLinkLayerStatsCollection_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::disableLinkLayerStatsCollectionInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getLinkLayerStats(
-    getLinkLayerStats_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::getLinkLayerStatsInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiStaIface::startRssiMonitoring(
-    uint32_t cmd_id,
-    int32_t max_rssi,
-    int32_t min_rssi,
-    startRssiMonitoring_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::startRssiMonitoringInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         max_rssi,
-                         min_rssi);
-}
-
-Return<void> WifiStaIface::stopRssiMonitoring(
-    uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::stopRssiMonitoringInternal,
-                         hidl_status_cb,
-                         cmd_id);
-}
-
-Return<void> WifiStaIface::getRoamingCapabilities(
-    getRoamingCapabilities_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::getRoamingCapabilitiesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiStaIface::configureRoaming(
-    const StaRoamingConfig& config, configureRoaming_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::configureRoamingInternal,
-                         hidl_status_cb,
-                         config);
-}
-
-Return<void> WifiStaIface::setRoamingState(StaRoamingState state,
-                                           setRoamingState_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::setRoamingStateInternal,
-                         hidl_status_cb,
-                         state);
-}
-
-Return<void> WifiStaIface::enableNdOffload(bool enable,
-                                           enableNdOffload_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::enableNdOffloadInternal,
-                         hidl_status_cb,
-                         enable);
-}
-
-Return<void> WifiStaIface::startSendingKeepAlivePackets(
-    uint32_t cmd_id,
-    const hidl_vec<uint8_t>& ip_packet_data,
-    uint16_t ether_type,
-    const hidl_array<uint8_t, 6>& src_address,
-    const hidl_array<uint8_t, 6>& dst_address,
-    uint32_t period_in_ms,
-    startSendingKeepAlivePackets_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::startSendingKeepAlivePacketsInternal,
-                         hidl_status_cb,
-                         cmd_id,
-                         ip_packet_data,
-                         ether_type,
-                         src_address,
-                         dst_address,
-                         period_in_ms);
-}
-
-Return<void> WifiStaIface::stopSendingKeepAlivePackets(
-    uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::stopSendingKeepAlivePacketsInternal,
-                         hidl_status_cb,
-                         cmd_id);
-}
-
-Return<void> WifiStaIface::setScanningMacOui(
-    const hidl_array<uint8_t, 3>& oui, setScanningMacOui_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::setScanningMacOuiInternal,
-                         hidl_status_cb,
-                         oui);
-}
-
-Return<void> WifiStaIface::startDebugPacketFateMonitoring(
-    startDebugPacketFateMonitoring_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::startDebugPacketFateMonitoringInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getDebugTxPacketFates(
-    getDebugTxPacketFates_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::getDebugTxPacketFatesInternal,
-                         hidl_status_cb);
-}
-
-Return<void> WifiStaIface::getDebugRxPacketFates(
-    getDebugRxPacketFates_cb hidl_status_cb) {
-  return validateAndCall(this,
-                         WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
-                         &WifiStaIface::getDebugRxPacketFatesInternal,
-                         hidl_status_cb);
-}
-
-std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
-  return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
-}
-
-std::pair<WifiStatus, IfaceType> WifiStaIface::getTypeInternal() {
-  return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::STA};
-}
-
-WifiStatus WifiStaIface::registerEventCallbackInternal(
-    const sp<IWifiStaIfaceEventCallback>& callback) {
-  if (!event_cb_handler_.addCallback(callback)) {
-    return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-  }
-  return createWifiStatus(WifiStatusCode::SUCCESS);
-}
-
-std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
-  legacy_hal::wifi_error legacy_status;
-  uint32_t legacy_feature_set;
-  std::tie(legacy_status, legacy_feature_set) =
-      legacy_hal_.lock()->getSupportedFeatureSet();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), 0};
-  }
-  uint32_t legacy_logger_feature_set;
-  std::tie(legacy_status, legacy_logger_feature_set) =
-      legacy_hal_.lock()->getLoggerSupportedFeatureSet();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    // some devices don't support querying logger feature set
-    legacy_logger_feature_set = 0;
-  }
-  uint32_t hidl_caps;
-  if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
-          legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, StaApfPacketFilterCapabilities>
-WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
-  legacy_hal::wifi_error legacy_status;
-  legacy_hal::PacketFilterCapabilities legacy_caps;
-  std::tie(legacy_status, legacy_caps) =
-      legacy_hal_.lock()->getPacketFilterCapabilities();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  StaApfPacketFilterCapabilities hidl_caps;
-  if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps,
-                                                            &hidl_caps)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiStaIface::installApfPacketFilterInternal(
-    uint32_t /* cmd_id */, const std::vector<uint8_t>& program) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->setPacketFilter(program);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, StaBackgroundScanCapabilities>
-WifiStaIface::getBackgroundScanCapabilitiesInternal() {
-  legacy_hal::wifi_error legacy_status;
-  legacy_hal::wifi_gscan_capabilities legacy_caps;
-  std::tie(legacy_status, legacy_caps) =
-      legacy_hal_.lock()->getGscanCapabilities();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  StaBackgroundScanCapabilities hidl_caps;
-  if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps,
-                                                              &hidl_caps)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-WifiStaIface::getValidFrequenciesForBandInternal(WifiBand band) {
-  static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t), "Size mismatch");
-  legacy_hal::wifi_error legacy_status;
-  std::vector<uint32_t> valid_frequencies;
-  std::tie(legacy_status, valid_frequencies) =
-      legacy_hal_.lock()->getValidFrequenciesForBand(
-          hidl_struct_util::convertHidlWifiBandToLegacy(band));
-  return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
-}
-
-WifiStatus WifiStaIface::startBackgroundScanInternal(
-    uint32_t cmd_id, const StaBackgroundScanParameters& params) {
-  legacy_hal::wifi_scan_cmd_params legacy_params;
-  if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params,
-                                                        &legacy_params)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  android::wp<WifiStaIface> weak_ptr_this(this);
-  const auto& on_failure_callback =
-      [weak_ptr_this](legacy_hal::wifi_request_id id) {
-        const auto shared_ptr_this = weak_ptr_this.promote();
-        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-          LOG(ERROR) << "Callback invoked on an invalid object";
-          return;
-        }
-        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-          if (!callback->onBackgroundScanFailure(id).isOk()) {
-            LOG(ERROR) << "Failed to invoke onBackgroundScanFailure callback";
-          }
-        }
-      };
-  const auto& on_results_callback = [weak_ptr_this](
-      legacy_hal::wifi_request_id id,
-      const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
-    const auto shared_ptr_this = weak_ptr_this.promote();
-    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-      LOG(ERROR) << "Callback invoked on an invalid object";
-      return;
-    }
-    std::vector<StaScanData> hidl_scan_datas;
-    if (!hidl_struct_util::convertLegacyVectorOfCachedGscanResultsToHidl(
-            results, &hidl_scan_datas)) {
-      LOG(ERROR) << "Failed to convert scan results to HIDL structs";
-      return;
-    }
-    for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-      if (!callback->onBackgroundScanResults(id, hidl_scan_datas).isOk()) {
-        LOG(ERROR) << "Failed to invoke onBackgroundScanResults callback";
-      }
-    }
-  };
-  const auto& on_full_result_callback = [weak_ptr_this](
-      legacy_hal::wifi_request_id id,
-      const legacy_hal::wifi_scan_result* result,
-      uint32_t buckets_scanned) {
-    const auto shared_ptr_this = weak_ptr_this.promote();
-    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-      LOG(ERROR) << "Callback invoked on an invalid object";
-      return;
-    }
-    StaScanResult hidl_scan_result;
-    if (!hidl_struct_util::convertLegacyGscanResultToHidl(
-            *result, true, &hidl_scan_result)) {
-      LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
-      return;
-    }
-    for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-      if (!callback->onBackgroundFullScanResult(
-              id, buckets_scanned, hidl_scan_result).isOk()) {
-        LOG(ERROR) << "Failed to invoke onBackgroundFullScanResult callback";
-      }
-    }
-  };
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->startGscan(cmd_id,
-                                     legacy_params,
-                                     on_failure_callback,
-                                     on_results_callback,
-                                     on_full_result_callback);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
-  legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->stopGscan(cmd_id);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->enableLinkLayerStats(debug);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->disableLinkLayerStats();
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, StaLinkLayerStats>
-WifiStaIface::getLinkLayerStatsInternal() {
-  legacy_hal::wifi_error legacy_status;
-  legacy_hal::LinkLayerStats legacy_stats;
-  std::tie(legacy_status, legacy_stats) =
-      legacy_hal_.lock()->getLinkLayerStats();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  StaLinkLayerStats hidl_stats;
-  if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
-                                                           &hidl_stats)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
-}
-
-WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id,
-                                                     int32_t max_rssi,
-                                                     int32_t min_rssi) {
-  android::wp<WifiStaIface> weak_ptr_this(this);
-  const auto& on_threshold_breached_callback = [weak_ptr_this](
-      legacy_hal::wifi_request_id id,
-      std::array<uint8_t, 6> bssid,
-      int8_t rssi) {
-    const auto shared_ptr_this = weak_ptr_this.promote();
-    if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
-      LOG(ERROR) << "Callback invoked on an invalid object";
-      return;
-    }
-    for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-      if (!callback->onRssiThresholdBreached(id, bssid, rssi).isOk()) {
-        LOG(ERROR) << "Failed to invoke onRssiThresholdBreached callback";
-      }
-    }
-  };
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->startRssiMonitoring(
-          cmd_id, max_rssi, min_rssi, on_threshold_breached_callback);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->stopRssiMonitoring(cmd_id);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, StaRoamingCapabilities>
-WifiStaIface::getRoamingCapabilitiesInternal() {
-  legacy_hal::wifi_error legacy_status;
-  legacy_hal::wifi_roaming_capabilities legacy_caps;
-  std::tie(legacy_status, legacy_caps) =
-      legacy_hal_.lock()->getRoamingCapabilities();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  StaRoamingCapabilities hidl_caps;
-  if (!hidl_struct_util::convertLegacyRoamingCapabilitiesToHidl(legacy_caps,
-                                                                &hidl_caps)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
-}
-
-WifiStatus WifiStaIface::configureRoamingInternal(
-    const StaRoamingConfig& config) {
-  legacy_hal::wifi_roaming_config legacy_config;
-  if (!hidl_struct_util::convertHidlRoamingConfigToLegacy(config,
-                                                          &legacy_config)) {
-    return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-  }
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->configureRoaming(legacy_config);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->enableFirmwareRoaming(
-          hidl_struct_util::convertHidlRoamingStateToLegacy(state));
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->configureNdOffload(enable);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
-    uint32_t cmd_id,
-    const std::vector<uint8_t>& ip_packet_data,
-    uint16_t /* ether_type */,
-    const std::array<uint8_t, 6>& src_address,
-    const std::array<uint8_t, 6>& dst_address,
-    uint32_t period_in_ms) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->startSendingOffloadedPacket(
-          cmd_id, ip_packet_data, src_address, dst_address, period_in_ms);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->stopSendingOffloadedPacket(cmd_id);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::setScanningMacOuiInternal(
-    const std::array<uint8_t, 3>& oui) {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->setScanningMacOui(oui);
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
-  legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->startPktFateMonitoring();
-  return createWifiStatusFromLegacyError(legacy_status);
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
-WifiStaIface::getDebugTxPacketFatesInternal() {
-  legacy_hal::wifi_error legacy_status;
-  std::vector<legacy_hal::wifi_tx_report> legacy_fates;
-  std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getTxPktFates();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  std::vector<WifiDebugTxPacketFateReport> hidl_fates;
-  if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(
-          legacy_fates, &hidl_fates)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
-}
-
-std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
-WifiStaIface::getDebugRxPacketFatesInternal() {
-  legacy_hal::wifi_error legacy_status;
-  std::vector<legacy_hal::wifi_rx_report> legacy_fates;
-  std::tie(legacy_status, legacy_fates) = legacy_hal_.lock()->getRxPktFates();
-  if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-    return {createWifiStatusFromLegacyError(legacy_status), {}};
-  }
-  std::vector<WifiDebugRxPacketFateReport> hidl_fates;
-  if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(
-          legacy_fates, &hidl_fates)) {
-    return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
-  }
-  return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi_sta_iface.h b/wifi/1.1/default/wifi_sta_iface.h
deleted file mode 100644
index 587a5de..0000000
--- a/wifi/1.1/default/wifi_sta_iface.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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 WIFI_STA_IFACE_H_
-#define WIFI_STA_IFACE_H_
-
-#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiStaIface.h>
-#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-
-#include "hidl_callback_util.h"
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-/**
- * HIDL interface object used to control a STA Iface instance.
- */
-class WifiStaIface : public V1_0::IWifiStaIface {
- public:
-  WifiStaIface(const std::string& ifname,
-               const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
-  // Refer to |WifiChip::invalidate()|.
-  void invalidate();
-  bool isValid();
-  std::set<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
-
-  // HIDL methods exposed.
-  Return<void> getName(getName_cb hidl_status_cb) override;
-  Return<void> getType(getType_cb hidl_status_cb) override;
-  Return<void> registerEventCallback(
-      const sp<IWifiStaIfaceEventCallback>& callback,
-      registerEventCallback_cb hidl_status_cb) override;
-  Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
-  Return<void> getApfPacketFilterCapabilities(
-      getApfPacketFilterCapabilities_cb hidl_status_cb) override;
-  Return<void> installApfPacketFilter(
-      uint32_t cmd_id,
-      const hidl_vec<uint8_t>& program,
-      installApfPacketFilter_cb hidl_status_cb) override;
-  Return<void> getBackgroundScanCapabilities(
-      getBackgroundScanCapabilities_cb hidl_status_cb) override;
-  Return<void> getValidFrequenciesForBand(
-      WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override;
-  Return<void> startBackgroundScan(
-      uint32_t cmd_id,
-      const StaBackgroundScanParameters& params,
-      startBackgroundScan_cb hidl_status_cb) override;
-  Return<void> stopBackgroundScan(
-      uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) override;
-  Return<void> enableLinkLayerStatsCollection(
-      bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) override;
-  Return<void> disableLinkLayerStatsCollection(
-      disableLinkLayerStatsCollection_cb hidl_status_cb) override;
-  Return<void> getLinkLayerStats(getLinkLayerStats_cb hidl_status_cb) override;
-  Return<void> startRssiMonitoring(
-      uint32_t cmd_id,
-      int32_t max_rssi,
-      int32_t min_rssi,
-      startRssiMonitoring_cb hidl_status_cb) override;
-  Return<void> stopRssiMonitoring(
-      uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
-  Return<void> getRoamingCapabilities(
-      getRoamingCapabilities_cb hidl_status_cb) override;
-  Return<void> configureRoaming(const StaRoamingConfig& config,
-                                configureRoaming_cb hidl_status_cb) override;
-  Return<void> setRoamingState(StaRoamingState state,
-                               setRoamingState_cb hidl_status_cb) override;
-  Return<void> enableNdOffload(bool enable,
-                               enableNdOffload_cb hidl_status_cb) override;
-  Return<void> startSendingKeepAlivePackets(
-      uint32_t cmd_id,
-      const hidl_vec<uint8_t>& ip_packet_data,
-      uint16_t ether_type,
-      const hidl_array<uint8_t, 6>& src_address,
-      const hidl_array<uint8_t, 6>& dst_address,
-      uint32_t period_in_ms,
-      startSendingKeepAlivePackets_cb hidl_status_cb) override;
-  Return<void> stopSendingKeepAlivePackets(
-      uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) override;
-  Return<void> setScanningMacOui(const hidl_array<uint8_t, 3>& oui,
-                                 setScanningMacOui_cb hidl_status_cb) override;
-  Return<void> startDebugPacketFateMonitoring(
-      startDebugPacketFateMonitoring_cb hidl_status_cb) override;
-  Return<void> getDebugTxPacketFates(
-      getDebugTxPacketFates_cb hidl_status_cb) override;
-  Return<void> getDebugRxPacketFates(
-      getDebugRxPacketFates_cb hidl_status_cb) override;
-
- private:
-  // Corresponding worker functions for the HIDL methods.
-  std::pair<WifiStatus, std::string> getNameInternal();
-  std::pair<WifiStatus, IfaceType> getTypeInternal();
-  WifiStatus registerEventCallbackInternal(
-      const sp<IWifiStaIfaceEventCallback>& callback);
-  std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
-  std::pair<WifiStatus, StaApfPacketFilterCapabilities>
-  getApfPacketFilterCapabilitiesInternal();
-  WifiStatus installApfPacketFilterInternal(
-      uint32_t cmd_id, const std::vector<uint8_t>& program);
-  std::pair<WifiStatus, StaBackgroundScanCapabilities>
-  getBackgroundScanCapabilitiesInternal();
-  std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
-  getValidFrequenciesForBandInternal(WifiBand band);
-  WifiStatus startBackgroundScanInternal(
-      uint32_t cmd_id, const StaBackgroundScanParameters& params);
-  WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
-  WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
-  WifiStatus disableLinkLayerStatsCollectionInternal();
-  std::pair<WifiStatus, StaLinkLayerStats> getLinkLayerStatsInternal();
-  WifiStatus startRssiMonitoringInternal(uint32_t cmd_id,
-                                         int32_t max_rssi,
-                                         int32_t min_rssi);
-  WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
-  std::pair<WifiStatus, StaRoamingCapabilities>
-  getRoamingCapabilitiesInternal();
-  WifiStatus configureRoamingInternal(const StaRoamingConfig& config);
-  WifiStatus setRoamingStateInternal(StaRoamingState state);
-  WifiStatus enableNdOffloadInternal(bool enable);
-  WifiStatus startSendingKeepAlivePacketsInternal(
-      uint32_t cmd_id,
-      const std::vector<uint8_t>& ip_packet_data,
-      uint16_t ether_type,
-      const std::array<uint8_t, 6>& src_address,
-      const std::array<uint8_t, 6>& dst_address,
-      uint32_t period_in_ms);
-  WifiStatus stopSendingKeepAlivePacketsInternal(uint32_t cmd_id);
-  WifiStatus setScanningMacOuiInternal(const std::array<uint8_t, 3>& oui);
-  WifiStatus startDebugPacketFateMonitoringInternal();
-  std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
-  getDebugTxPacketFatesInternal();
-  std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
-  getDebugRxPacketFatesInternal();
-
-  std::string ifname_;
-  std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
-  bool is_valid_;
-  hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback>
-      event_cb_handler_;
-
-  DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_STA_IFACE_H_
diff --git a/wifi/1.1/default/wifi_status_util.cpp b/wifi/1.1/default/wifi_status_util.cpp
deleted file mode 100644
index 3a85e09..0000000
--- a/wifi/1.1/default/wifi_status_util.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.
- */
-
-#include "wifi_status_util.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-
-std::string legacyErrorToString(legacy_hal::wifi_error error) {
-  switch (error) {
-    case legacy_hal::WIFI_SUCCESS:
-      return "SUCCESS";
-    case legacy_hal::WIFI_ERROR_UNINITIALIZED:
-      return "UNINITIALIZED";
-    case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
-      return "NOT_AVAILABLE";
-    case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
-      return "NOT_SUPPORTED";
-    case legacy_hal::WIFI_ERROR_INVALID_ARGS:
-      return "INVALID_ARGS";
-    case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
-      return "INVALID_REQUEST_ID";
-    case legacy_hal::WIFI_ERROR_TIMED_OUT:
-      return "TIMED_OUT";
-    case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
-      return "TOO_MANY_REQUESTS";
-    case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
-      return "OUT_OF_MEMORY";
-    case legacy_hal::WIFI_ERROR_BUSY:
-      return "BUSY";
-    case legacy_hal::WIFI_ERROR_UNKNOWN:
-      return "UNKNOWN";
-  }
-}
-
-WifiStatus createWifiStatus(WifiStatusCode code,
-                            const std::string& description) {
-  return {code, description};
-}
-
-WifiStatus createWifiStatus(WifiStatusCode code) {
-  return createWifiStatus(code, "");
-}
-
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
-                                           const std::string& desc) {
-  switch (error) {
-    case legacy_hal::WIFI_ERROR_UNINITIALIZED:
-    case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
-      return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
-
-    case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
-      return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
-
-    case legacy_hal::WIFI_ERROR_INVALID_ARGS:
-    case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
-      return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
-
-    case legacy_hal::WIFI_ERROR_TIMED_OUT:
-      return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
-                              desc + ", timed out");
-
-    case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
-      return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
-                              desc + ", too many requests");
-
-    case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
-      return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
-                              desc + ", out of memory");
-
-    case legacy_hal::WIFI_ERROR_BUSY:
-      return createWifiStatus(WifiStatusCode::ERROR_BUSY);
-
-    case legacy_hal::WIFI_ERROR_NONE:
-      return createWifiStatus(WifiStatusCode::SUCCESS, desc);
-
-    case legacy_hal::WIFI_ERROR_UNKNOWN:
-      return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
-  }
-}
-
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
-  return createWifiStatusFromLegacyError(error, "");
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.1/default/wifi_status_util.h b/wifi/1.1/default/wifi_status_util.h
deleted file mode 100644
index cc93d66..0000000
--- a/wifi/1.1/default/wifi_status_util.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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 WIFI_STATUS_UTIL_H_
-#define WIFI_STATUS_UTIL_H_
-
-#include <android/hardware/wifi/1.0/IWifi.h>
-
-#include "wifi_legacy_hal.h"
-
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_1 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-std::string legacyErrorToString(legacy_hal::wifi_error error);
-WifiStatus createWifiStatus(WifiStatusCode code,
-                            const std::string& description);
-WifiStatus createWifiStatus(WifiStatusCode code);
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
-                                           const std::string& description);
-WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
-
-#endif  // WIFI_STATUS_UTIL_H_
diff --git a/wifi/1.2/Android.bp b/wifi/1.2/Android.bp
new file mode 100644
index 0000000..f41324e
--- /dev/null
+++ b/wifi/1.2/Android.bp
@@ -0,0 +1,30 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IWifi.hal",
+        "IWifiChip.hal",
+        "IWifiChipEventCallback.hal",
+        "IWifiNanIface.hal",
+        "IWifiNanIfaceEventCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "NanConfigRequestSupplemental",
+        "NanDataPathChannelInfo",
+        "NanDataPathConfirmInd",
+        "NanDataPathScheduleUpdateInd",
+    ],
+    gen_java: true,
+}
+
diff --git a/wifi/1.2/IWifi.hal b/wifi/1.2/IWifi.hal
new file mode 100644
index 0000000..7f47027
--- /dev/null
+++ b/wifi/1.2/IWifi.hal
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.1::IWifi;
+
+/**
+ * This is the root of the HAL module and is the interface returned when
+ * loading an implementation of the Wi-Fi HAL. There must be at most one
+ * module loaded in the system.
+ * IWifi.getChip() may return either a @1.0::IWifiChip or @1.1::IWifiChip
+ * or @1.2:IWifiChip
+ */
+interface IWifi extends @1.1::IWifi {
+};
diff --git a/wifi/1.2/IWifiChip.hal b/wifi/1.2/IWifiChip.hal
new file mode 100644
index 0000000..480c5a2
--- /dev/null
+++ b/wifi/1.2/IWifiChip.hal
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::WifiStatus;
+import @1.1::IWifiChip;
+import IWifiChipEventCallback;
+
+/**
+ * Interface that represents a chip that must be configured as a single unit.
+ * The HAL/driver/firmware will be responsible for determining which phy is used
+ * to perform operations like NAN, RTT, etc.
+ */
+interface IWifiChip extends @1.1::IWifiChip {
+    /**
+     * Capabilities exposed by this chip.
+     */
+    enum ChipCapabilityMask : @1.1::IWifiChip.ChipCapabilityMask {
+        /**
+         * Set/Reset Tx Power limits.
+         */
+         USE_BODY_HEAD_SAR = 1 << 11
+    };
+
+    /**
+     * List of preset wifi radio TX power levels for different scenarios.
+     * The actual power values (typically varies based on the channel,
+     * 802.11 connection type, number of MIMO streams, etc) for each scenario
+     * is defined by the OEM as a BDF file since it varies for each wifi chip
+     * vendor and device.
+     */
+    enum TxPowerScenario : @1.1::IWifiChip.TxPowerScenario {
+        ON_HEAD_CELL_OFF = 1,
+        ON_HEAD_CELL_ON  = 2,
+        ON_BODY_CELL_OFF = 3,
+        ON_BODY_CELL_ON  = 4
+    };
+
+    /**
+     * API to select one of the preset TX power scenarios.
+     *
+     * The framework must invoke this method with the appropriate scenario to let
+     * the wifi chip change it's transmitting power levels.
+     * OEM's should define various power profiles for each of the scenarios
+     * above (defined in |TxPowerScenario|) in a vendor extension.
+     *
+     * @param scenario One of the preselected scenarios defined in
+     *        |TxPowerScenario|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+     *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *         |WifiStatusCode.NOT_AVAILABLE|,
+     *         |WifiStatusCode.UNKNOWN|
+     */
+    selectTxPowerScenario_1_2(TxPowerScenario scenario) generates (WifiStatus status);
+
+    /**
+     * Requests notifications of significant events on this chip. Multiple calls
+     * to this must register multiple callbacks each of which must receive all
+     * events.
+     *
+     * @param callback An instance of the |IWifiChipEventCallback| HIDL interface
+     *        object.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|
+     */
+    registerEventCallback_1_2(IWifiChipEventCallback callback)
+        generates (WifiStatus status);
+};
diff --git a/wifi/1.2/IWifiChipEventCallback.hal b/wifi/1.2/IWifiChipEventCallback.hal
new file mode 100644
index 0000000..5d2e7e9
--- /dev/null
+++ b/wifi/1.2/IWifiChipEventCallback.hal
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::IWifiChipEventCallback;
+import @1.0::WifiBand;
+
+/**
+ * Wifi chip event callbacks.
+ */
+interface IWifiChipEventCallback extends @1.0::IWifiChipEventCallback {
+    /**
+     * Struct describing the state of each iface operating on the radio chain
+     * (hardware MAC) on the device.
+     */
+    struct IfaceInfo {
+        /** Name of the interface (For ex: "wlan0"). */
+        string name;
+        /** Wifi channel on which this interface is operating. */
+        uint32_t channel;
+    };
+
+    /**
+     * Struct describing the state of each hardware radio chain (hardware MAC)
+     * on the device.
+     */
+    struct RadioModeInfo {
+        /**
+         * Identifier for this radio chain. This is vendor dependent & used
+         * only for debugging purposes.
+         */
+        uint32_t radioId;
+        /**
+         * List of bands on which this radio chain is operating.
+         * Can be one of:
+         * a) WifiBand.BAND_24GHZ => 2.4Ghz.
+         * b) WifiBand.BAND_5GHZ => 5Ghz.
+         * c) WifiBand.BAND_24GHZ_5GHZ = 2.4Ghz + 5Ghz (Radio is time sharing
+         * across the 2 bands).
+         */
+        WifiBand bandInfo;
+        /** List of interfaces on this radio chain (hardware MAC). */
+        vec<IfaceInfo> ifaceInfos;
+    };
+
+    /**
+     * Asynchronous callback indicating a radio mode change.
+     * Radio mode change could be a result of:
+     * a) Bringing up concurrent interfaces (For ex: STA + AP).
+     * b) Change in operating band of one of the concurrent interfaces (For ex:
+     * STA connection moved from 2.4G to 5G)
+     *
+     * @param radioModeInfos List of RadioModeInfo structures for each
+     * radio chain (hardware MAC) on the device.
+     */
+    oneway onRadioModeChange(vec<RadioModeInfo> radioModeInfos);
+};
diff --git a/wifi/1.2/IWifiNanIface.hal b/wifi/1.2/IWifiNanIface.hal
new file mode 100644
index 0000000..0260162
--- /dev/null
+++ b/wifi/1.2/IWifiNanIface.hal
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::CommandIdShort;
+import @1.0::IWifiNanIface;
+import @1.0::NanConfigRequest;
+import @1.0::NanEnableRequest;
+import @1.0::WifiStatus;
+import IWifiNanIfaceEventCallback;
+
+/**
+ * Interface used to represent a single NAN (Neighbour Aware Network) iface.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIface extends @1.0::IWifiNanIface {
+    /**
+     * Requests notifications of significant events on this iface. Multiple calls
+     * to this must register multiple callbacks each of which must receive all
+     * events.
+     *
+     * Note: supersedes the @1.0::IWifiNanIface.registerEventCallback() method which is deprecated
+     * as of HAL version 1.2.
+     *
+     * @param callback An instance of the |IWifiNanIfaceEventCallback| HIDL interface
+     *        object.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+     */
+    registerEventCallback_1_2(IWifiNanIfaceEventCallback callback)
+        generates (WifiStatus status);
+
+    /**
+     * Enable NAN: configures and activates NAN clustering (does not start
+     * a discovery session or set up data-interfaces or data-paths). Use the
+     * |IWifiNanIface.configureRequest| method to change the configuration of an already enabled
+     * NAN interface.
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyEnableResponse|.
+     *
+     * Note: supersedes the @1.0::IWifiNanIface.enableRequest() method which is deprecated as of
+     * HAL version 1.2.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg1 Instance of |NanEnableRequest|.
+     * @param msg2 Instance of |NanConfigRequestSupplemental|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    enableRequest_1_2(CommandIdShort cmdId, NanEnableRequest msg1,
+                      NanConfigRequestSupplemental msg2)
+        generates (WifiStatus status);
+
+    /**
+     * Configure NAN: configures an existing NAN functionality (i.e. assumes
+     * |IWifiNanIface.enableRequest| already submitted and succeeded).
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyConfigResponse|.
+     *
+     * Note: supersedes the @1.0::IWifiNanIface.configRequest() method which is deprecated as of
+     * HAL version 1.2.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg1 Instance of |NanConfigRequest|.
+     * @param msg1 Instance of |NanConfigRequestSupplemental|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    configRequest_1_2(CommandIdShort cmdId, NanConfigRequest msg1,
+                      NanConfigRequestSupplemental msg2)
+        generates (WifiStatus status);
+};
diff --git a/wifi/1.2/IWifiNanIfaceEventCallback.hal b/wifi/1.2/IWifiNanIfaceEventCallback.hal
new file mode 100644
index 0000000..efd5479
--- /dev/null
+++ b/wifi/1.2/IWifiNanIfaceEventCallback.hal
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::IWifiNanIfaceEventCallback;
+
+/**
+ * NAN Response and Asynchronous Event Callbacks.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIfaceEventCallback extends @1.0::IWifiNanIfaceEventCallback {
+    /**
+     * Asynchronous callback indicating a data-path (NDP) setup has been completed: received by
+     * both Initiator and Responder.
+     *
+     * Note: supersedes the @1.0::IWifiNanIfaceEventCallback.eventDataPathConfirm() method which is
+     * deprecated as of HAL version 1.2.
+     *
+     * @param event: NanDataPathConfirmInd containing event details.
+     */
+    oneway eventDataPathConfirm_1_2(NanDataPathConfirmInd event);
+
+    /**
+     * Asynchronous callback indicating a data-path (NDP) schedule has been updated (e.g. channels
+     * have been changed).
+     *
+     * @param event: NanDataPathScheduleUpdateInd containing event details.
+     */
+    oneway eventDataPathScheduleUpdate(NanDataPathScheduleUpdateInd event);
+};
\ No newline at end of file
diff --git a/wifi/1.2/default/Android.mk b/wifi/1.2/default/Android.mk
new file mode 100644
index 0000000..978cf63
--- /dev/null
+++ b/wifi/1.2/default/Android.mk
@@ -0,0 +1,121 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+LOCAL_PATH := $(call my-dir)
+
+###
+### android.hardware.wifi static library
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-lib
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+ifdef WIFI_HIDL_FEATURE_AWARE
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_AWARE
+endif
+ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE
+LOCAL_CPPFLAGS += -DWIFI_HIDL_FEATURE_DUAL_INTERFACE
+endif
+LOCAL_SRC_FILES := \
+    hidl_struct_util.cpp \
+    hidl_sync_util.cpp \
+    ringbuffer.cpp \
+    wifi.cpp \
+    wifi_ap_iface.cpp \
+    wifi_chip.cpp \
+    wifi_feature_flags.cpp \
+    wifi_legacy_hal.cpp \
+    wifi_legacy_hal_stubs.cpp \
+    wifi_mode_controller.cpp \
+    wifi_nan_iface.cpp \
+    wifi_p2p_iface.cpp \
+    wifi_rtt_controller.cpp \
+    wifi_sta_iface.cpp \
+    wifi_status_util.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    libhidltransport \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+include $(BUILD_STATIC_LIBRARY)
+
+###
+### android.hardware.wifi daemon
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_CPPFLAGS := -Wall -Werror -Wextra
+LOCAL_SRC_FILES := \
+    service.cpp
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    libhidltransport \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2
+LOCAL_STATIC_LIBRARIES := \
+    android.hardware.wifi@1.0-service-lib
+LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
+include $(BUILD_EXECUTABLE)
+
+###
+### android.hardware.wifi unit tests.
+###
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi@1.0-service-tests
+LOCAL_PROPRIETARY_MODULE := true
+LOCAL_SRC_FILES := \
+    tests/hidl_struct_util_unit_tests.cpp \
+    tests/main.cpp \
+    tests/mock_wifi_feature_flags.cpp \
+    tests/mock_wifi_legacy_hal.cpp \
+    tests/mock_wifi_mode_controller.cpp \
+    tests/ringbuffer_unit_tests.cpp \
+    tests/wifi_chip_unit_tests.cpp
+LOCAL_STATIC_LIBRARIES := \
+    libgmock \
+    libgtest \
+    android.hardware.wifi@1.0-service-lib
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
+    libhidlbase \
+    libhidltransport \
+    liblog \
+    libnl \
+    libutils \
+    libwifi-hal \
+    libwifi-system-iface \
+    android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
+    android.hardware.wifi@1.2
+include $(BUILD_NATIVE_TEST)
diff --git a/wifi/1.1/default/OWNERS b/wifi/1.2/default/OWNERS
similarity index 100%
rename from wifi/1.1/default/OWNERS
rename to wifi/1.2/default/OWNERS
diff --git a/wifi/1.1/default/THREADING.README b/wifi/1.2/default/THREADING.README
similarity index 100%
rename from wifi/1.1/default/THREADING.README
rename to wifi/1.2/default/THREADING.README
diff --git a/wifi/1.2/default/android.hardware.wifi@1.0-service.rc b/wifi/1.2/default/android.hardware.wifi@1.0-service.rc
new file mode 100644
index 0000000..eecb6d0
--- /dev/null
+++ b/wifi/1.2/default/android.hardware.wifi@1.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
+    class hal
+    user wifi
+    group wifi gps
diff --git a/wifi/1.2/default/hidl_callback_util.h b/wifi/1.2/default/hidl_callback_util.h
new file mode 100644
index 0000000..97f312a
--- /dev/null
+++ b/wifi/1.2/default/hidl_callback_util.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HIDL_CALLBACK_UTIL_H_
+#define HIDL_CALLBACK_UTIL_H_
+
+#include <set>
+
+#include <hidl/HidlSupport.h>
+
+namespace {
+// Type of callback invoked by the death handler.
+using on_death_cb_function = std::function<void(uint64_t)>;
+
+// Private class used to keep track of death of individual
+// callbacks stored in HidlCallbackHandler.
+template <typename CallbackType>
+class HidlDeathHandler : public android::hardware::hidl_death_recipient {
+   public:
+    HidlDeathHandler(const on_death_cb_function& user_cb_function)
+        : cb_function_(user_cb_function) {}
+    ~HidlDeathHandler() = default;
+
+    // Death notification for callbacks.
+    void serviceDied(
+        uint64_t cookie,
+        const android::wp<android::hidl::base::V1_0::IBase>& /* who */)
+        override {
+        cb_function_(cookie);
+    }
+
+   private:
+    on_death_cb_function cb_function_;
+
+    DISALLOW_COPY_AND_ASSIGN(HidlDeathHandler);
+};
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace hidl_callback_util {
+template <typename CallbackType>
+// Provides a class to manage callbacks for the various HIDL interfaces and
+// handle the death of the process hosting each callback.
+class HidlCallbackHandler {
+   public:
+    HidlCallbackHandler()
+        : death_handler_(new HidlDeathHandler<CallbackType>(
+              std::bind(&HidlCallbackHandler::onObjectDeath, this,
+                        std::placeholders::_1))) {}
+    ~HidlCallbackHandler() = default;
+
+    bool addCallback(const sp<CallbackType>& cb) {
+        // TODO(b/33818800): Can't compare proxies yet. So, use the cookie
+        // (callback proxy's raw pointer) to track the death of individual
+        // clients.
+        uint64_t cookie = reinterpret_cast<uint64_t>(cb.get());
+        if (cb_set_.find(cb) != cb_set_.end()) {
+            LOG(WARNING) << "Duplicate death notification registration";
+            return true;
+        }
+        if (!cb->linkToDeath(death_handler_, cookie)) {
+            LOG(ERROR) << "Failed to register death notification";
+            return false;
+        }
+        cb_set_.insert(cb);
+        return true;
+    }
+
+    const std::set<android::sp<CallbackType>>& getCallbacks() {
+        return cb_set_;
+    }
+
+    // Death notification for callbacks.
+    void onObjectDeath(uint64_t cookie) {
+        CallbackType* cb = reinterpret_cast<CallbackType*>(cookie);
+        const auto& iter = cb_set_.find(cb);
+        if (iter == cb_set_.end()) {
+            LOG(ERROR) << "Unknown callback death notification received";
+            return;
+        }
+        cb_set_.erase(iter);
+        LOG(DEBUG) << "Dead callback removed from list";
+    }
+
+    void invalidate() {
+        for (const sp<CallbackType>& cb : cb_set_) {
+            if (!cb->unlinkToDeath(death_handler_)) {
+                LOG(ERROR) << "Failed to deregister death notification";
+            }
+        }
+        cb_set_.clear();
+    }
+
+   private:
+    std::set<sp<CallbackType>> cb_set_;
+    sp<HidlDeathHandler<CallbackType>> death_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(HidlCallbackHandler);
+};
+
+}  // namespace hidl_callback_util
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+#endif  // HIDL_CALLBACK_UTIL_H_
diff --git a/wifi/1.2/default/hidl_return_util.h b/wifi/1.2/default/hidl_return_util.h
new file mode 100644
index 0000000..914c1b4
--- /dev/null
+++ b/wifi/1.2/default/hidl_return_util.h
@@ -0,0 +1,120 @@
+/*
+ * 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 HIDL_RETURN_UTIL_H_
+#define HIDL_RETURN_UTIL_H_
+
+#include "hidl_sync_util.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace hidl_return_util {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * These utility functions are used to invoke a method on the provided
+ * HIDL interface object.
+ * These functions checks if the provided HIDL interface object is valid.
+ * a) if valid, Invokes the corresponding internal implementation function of
+ * the HIDL method. It then invokes the HIDL continuation callback with
+ * the status and any returned values.
+ * b) if invalid, invokes the HIDL continuation callback with the
+ * provided error status and default values.
+ */
+// Use for HIDL methods which return only an instance of WifiStatus.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCall(
+    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+    const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        hidl_cb((obj->*work)(std::forward<Args>(args)...));
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid));
+    }
+    return Void();
+}
+
+// Use for HIDL methods which return only an instance of WifiStatus.
+// This version passes the global lock acquired to the body of the method.
+// Note: Only used by IWifi::stop() currently.
+template <typename ObjT, typename WorkFuncT, typename... Args>
+Return<void> validateAndCallWithLock(
+    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+    const std::function<void(const WifiStatus&)>& hidl_cb, Args&&... args) {
+    auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        hidl_cb((obj->*work)(&lock, std::forward<Args>(args)...));
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid));
+    }
+    return Void();
+}
+
+// Use for HIDL methods which return instance of WifiStatus and a single return
+// value.
+template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
+Return<void> validateAndCall(
+    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+    const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
+    Args&&... args) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
+        const WifiStatus& status = std::get<0>(ret_pair);
+        const auto& ret_value = std::get<1>(ret_pair);
+        hidl_cb(status, ret_value);
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid),
+                typename std::remove_reference<ReturnT>::type());
+    }
+    return Void();
+}
+
+// Use for HIDL methods which return instance of WifiStatus and 2 return
+// values.
+template <typename ObjT, typename WorkFuncT, typename ReturnT1,
+          typename ReturnT2, typename... Args>
+Return<void> validateAndCall(
+    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
+    const std::function<void(const WifiStatus&, ReturnT1, ReturnT2)>& hidl_cb,
+    Args&&... args) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (obj->isValid()) {
+        const auto& ret_tuple = (obj->*work)(std::forward<Args>(args)...);
+        const WifiStatus& status = std::get<0>(ret_tuple);
+        const auto& ret_value1 = std::get<1>(ret_tuple);
+        const auto& ret_value2 = std::get<2>(ret_tuple);
+        hidl_cb(status, ret_value1, ret_value2);
+    } else {
+        hidl_cb(createWifiStatus(status_code_if_invalid),
+                typename std::remove_reference<ReturnT1>::type(),
+                typename std::remove_reference<ReturnT2>::type());
+    }
+    return Void();
+}
+
+}  // namespace hidl_return_util
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+#endif  // HIDL_RETURN_UTIL_H_
diff --git a/wifi/1.2/default/hidl_struct_util.cpp b/wifi/1.2/default/hidl_struct_util.cpp
new file mode 100644
index 0000000..2e3e0ab
--- /dev/null
+++ b/wifi/1.2/default/hidl_struct_util.cpp
@@ -0,0 +1,2614 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "hidl_struct_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace hidl_struct_util {
+
+hidl_string safeConvertChar(const char* str, size_t max_len) {
+    const char* c = str;
+    size_t size = 0;
+    while (*c && (unsigned char)*c < 128 && size < max_len) {
+        ++size;
+        ++c;
+    }
+    return hidl_string(str, size);
+}
+
+IWifiChip::ChipCapabilityMask convertLegacyLoggerFeatureToHidlChipCapability(
+    uint32_t feature) {
+    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+    switch (feature) {
+        case legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED:
+            return HidlChipCaps::DEBUG_MEMORY_FIRMWARE_DUMP;
+        case legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED:
+            return HidlChipCaps::DEBUG_MEMORY_DRIVER_DUMP;
+        case legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED:
+            return HidlChipCaps::DEBUG_RING_BUFFER_CONNECT_EVENT;
+        case legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED:
+            return HidlChipCaps::DEBUG_RING_BUFFER_POWER_EVENT;
+        case legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED:
+            return HidlChipCaps::DEBUG_RING_BUFFER_WAKELOCK_EVENT;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask
+convertLegacyLoggerFeatureToHidlStaIfaceCapability(uint32_t feature) {
+    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+    switch (feature) {
+        case legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED:
+            return HidlStaIfaceCaps::DEBUG_PACKET_FATE;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
+    uint32_t feature) {
+    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+    switch (feature) {
+        case WIFI_FEATURE_SET_TX_POWER_LIMIT:
+            return HidlChipCaps::SET_TX_POWER_LIMIT;
+        case WIFI_FEATURE_USE_BODY_HEAD_SAR:
+            return HidlChipCaps::USE_BODY_HEAD_SAR;
+        case WIFI_FEATURE_D2D_RTT:
+            return HidlChipCaps::D2D_RTT;
+        case WIFI_FEATURE_D2AP_RTT:
+            return HidlChipCaps::D2AP_RTT;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+IWifiStaIface::StaIfaceCapabilityMask
+convertLegacyFeatureToHidlStaIfaceCapability(uint32_t feature) {
+    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+    switch (feature) {
+        case WIFI_FEATURE_GSCAN:
+            return HidlStaIfaceCaps::BACKGROUND_SCAN;
+        case WIFI_FEATURE_LINK_LAYER_STATS:
+            return HidlStaIfaceCaps::LINK_LAYER_STATS;
+        case WIFI_FEATURE_RSSI_MONITOR:
+            return HidlStaIfaceCaps::RSSI_MONITOR;
+        case WIFI_FEATURE_CONTROL_ROAMING:
+            return HidlStaIfaceCaps::CONTROL_ROAMING;
+        case WIFI_FEATURE_IE_WHITELIST:
+            return HidlStaIfaceCaps::PROBE_IE_WHITELIST;
+        case WIFI_FEATURE_SCAN_RAND:
+            return HidlStaIfaceCaps::SCAN_RAND;
+        case WIFI_FEATURE_INFRA_5G:
+            return HidlStaIfaceCaps::STA_5G;
+        case WIFI_FEATURE_HOTSPOT:
+            return HidlStaIfaceCaps::HOTSPOT;
+        case WIFI_FEATURE_PNO:
+            return HidlStaIfaceCaps::PNO;
+        case WIFI_FEATURE_TDLS:
+            return HidlStaIfaceCaps::TDLS;
+        case WIFI_FEATURE_TDLS_OFFCHANNEL:
+            return HidlStaIfaceCaps::TDLS_OFFCHANNEL;
+        case WIFI_FEATURE_CONFIG_NDO:
+            return HidlStaIfaceCaps::ND_OFFLOAD;
+        case WIFI_FEATURE_MKEEP_ALIVE:
+            return HidlStaIfaceCaps::KEEP_ALIVE;
+    };
+    CHECK(false) << "Unknown legacy feature: " << feature;
+    return {};
+}
+
+bool convertLegacyFeaturesToHidlChipCapabilities(
+    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint32_t* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+    for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_CONNECT_EVENT_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_POWER_EVENT_SUPPORTED,
+                               legacy_hal::WIFI_LOGGER_WAKE_LOCK_SUPPORTED}) {
+        if (feature & legacy_logger_feature_set) {
+            *hidl_caps |=
+                convertLegacyLoggerFeatureToHidlChipCapability(feature);
+        }
+    }
+    for (const auto feature : {WIFI_FEATURE_SET_TX_POWER_LIMIT,
+                               WIFI_FEATURE_USE_BODY_HEAD_SAR,
+                               WIFI_FEATURE_D2D_RTT, WIFI_FEATURE_D2AP_RTT}) {
+        if (feature & legacy_feature_set) {
+            *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
+        }
+    }
+    // There are no flags for these 3 in the legacy feature set. Adding them to
+    // the set because all the current devices support it.
+    *hidl_caps |= HidlChipCaps::DEBUG_RING_BUFFER_VENDOR_DATA;
+    *hidl_caps |= HidlChipCaps::DEBUG_HOST_WAKE_REASON_STATS;
+    *hidl_caps |= HidlChipCaps::DEBUG_ERROR_ALERTS;
+    return true;
+}
+
+WifiDebugRingBufferFlags convertLegacyDebugRingBufferFlagsToHidl(
+    uint32_t flag) {
+    switch (flag) {
+        case WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES:
+            return WifiDebugRingBufferFlags::HAS_BINARY_ENTRIES;
+        case WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES:
+            return WifiDebugRingBufferFlags::HAS_ASCII_ENTRIES;
+    };
+    CHECK(false) << "Unknown legacy flag: " << flag;
+    return {};
+}
+
+bool convertLegacyDebugRingBufferStatusToHidl(
+    const legacy_hal::wifi_ring_buffer_status& legacy_status,
+    WifiDebugRingBufferStatus* hidl_status) {
+    if (!hidl_status) {
+        return false;
+    }
+    *hidl_status = {};
+    hidl_status->ringName =
+        safeConvertChar(reinterpret_cast<const char*>(legacy_status.name),
+                        sizeof(legacy_status.name));
+    hidl_status->flags = 0;
+    for (const auto flag : {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES,
+                            WIFI_RING_BUFFER_FLAG_HAS_ASCII_ENTRIES}) {
+        if (flag & legacy_status.flags) {
+            hidl_status->flags |= static_cast<
+                std::underlying_type<WifiDebugRingBufferFlags>::type>(
+                convertLegacyDebugRingBufferFlagsToHidl(flag));
+        }
+    }
+    hidl_status->ringId = legacy_status.ring_id;
+    hidl_status->sizeInBytes = legacy_status.ring_buffer_byte_size;
+    // Calculate free size of the ring the buffer. We don't need to send the
+    // exact read/write pointers that were there in the legacy HAL interface.
+    if (legacy_status.written_bytes >= legacy_status.read_bytes) {
+        hidl_status->freeSizeInBytes =
+            legacy_status.ring_buffer_byte_size -
+            (legacy_status.written_bytes - legacy_status.read_bytes);
+    } else {
+        hidl_status->freeSizeInBytes =
+            legacy_status.read_bytes - legacy_status.written_bytes;
+    }
+    hidl_status->verboseLevel = legacy_status.verbose_level;
+    return true;
+}
+
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec) {
+    if (!hidl_status_vec) {
+        return false;
+    }
+    *hidl_status_vec = {};
+    for (const auto& legacy_status : legacy_status_vec) {
+        WifiDebugRingBufferStatus hidl_status;
+        if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status,
+                                                      &hidl_status)) {
+            return false;
+        }
+        hidl_status_vec->push_back(hidl_status);
+    }
+    return true;
+}
+
+bool convertLegacyWakeReasonStatsToHidl(
+    const legacy_hal::WakeReasonStats& legacy_stats,
+    WifiDebugHostWakeReasonStats* hidl_stats) {
+    if (!hidl_stats) {
+        return false;
+    }
+    *hidl_stats = {};
+    hidl_stats->totalCmdEventWakeCnt =
+        legacy_stats.wake_reason_cnt.total_cmd_event_wake;
+    hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
+    hidl_stats->totalDriverFwLocalWakeCnt =
+        legacy_stats.wake_reason_cnt.total_driver_fw_local_wake;
+    hidl_stats->driverFwLocalWakeCntPerType =
+        legacy_stats.driver_fw_local_wake_cnt;
+    hidl_stats->totalRxPacketWakeCnt =
+        legacy_stats.wake_reason_cnt.total_rx_data_wake;
+    hidl_stats->rxPktWakeDetails.rxUnicastCnt =
+        legacy_stats.wake_reason_cnt.rx_wake_details.rx_unicast_cnt;
+    hidl_stats->rxPktWakeDetails.rxMulticastCnt =
+        legacy_stats.wake_reason_cnt.rx_wake_details.rx_multicast_cnt;
+    hidl_stats->rxPktWakeDetails.rxBroadcastCnt =
+        legacy_stats.wake_reason_cnt.rx_wake_details.rx_broadcast_cnt;
+    hidl_stats->rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt =
+        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+            .ipv4_rx_multicast_addr_cnt;
+    hidl_stats->rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt =
+        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+            .ipv6_rx_multicast_addr_cnt;
+    hidl_stats->rxMulticastPkWakeDetails.otherRxMulticastAddrCnt =
+        legacy_stats.wake_reason_cnt.rx_multicast_wake_pkt_info
+            .other_rx_multicast_addr_cnt;
+    hidl_stats->rxIcmpPkWakeDetails.icmpPkt =
+        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Pkt =
+        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Ra =
+        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Na =
+        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na;
+    hidl_stats->rxIcmpPkWakeDetails.icmp6Ns =
+        legacy_stats.wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns;
+    return true;
+}
+
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
+    V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
+    switch (hidl_scenario) {
+        // This is the only supported scenario for V1_1
+      case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
+            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+    };
+    CHECK(false);
+}
+
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+    IWifiChip::TxPowerScenario hidl_scenario) {
+    switch (hidl_scenario) {
+        // This is the only supported scenario for V1_1
+        case IWifiChip::TxPowerScenario::VOICE_CALL:
+            return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
+        // Those are the supported scenarios for V1_2
+        case IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
+        case IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
+        case IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
+        case IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
+            return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
+    };
+    CHECK(false);
+}
+
+bool convertLegacyWifiMacInfoToHidl(
+    const legacy_hal::WifiMacInfo& legacy_mac_info,
+    IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
+    if (!hidl_radio_mode_info) {
+        return false;
+    }
+    *hidl_radio_mode_info = {};
+
+    hidl_radio_mode_info->radioId = legacy_mac_info.wlan_mac_id;
+    // Convert from bitmask of bands in the legacy HAL to enum value in
+    // the HIDL interface.
+    if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND &&
+        legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ_5GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_2_4_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_24GHZ;
+    } else if (legacy_mac_info.mac_band & legacy_hal::WLAN_MAC_5_0_BAND) {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_5GHZ;
+    } else {
+        hidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED;
+    }
+    std::vector<IWifiChipEventCallback::IfaceInfo> iface_info_vec;
+    for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
+        IWifiChipEventCallback::IfaceInfo iface_info;
+        iface_info.name = legacy_iface_info.name;
+        iface_info.channel = legacy_iface_info.channel;
+        iface_info_vec.push_back(iface_info);
+    }
+    hidl_radio_mode_info->ifaceInfos = iface_info_vec;
+    return true;
+}
+
+bool convertLegacyWifiMacInfosToHidl(
+    const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) {
+    if (!hidl_radio_mode_infos) {
+        return false;
+    }
+    *hidl_radio_mode_infos = {};
+
+    for (const auto& legacy_mac_info : legacy_mac_infos) {
+        IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
+        if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
+                                            &hidl_radio_mode_info)) {
+            return false;
+        }
+        hidl_radio_mode_infos->push_back(hidl_radio_mode_info);
+    }
+    return true;
+}
+
+bool convertLegacyFeaturesToHidlStaCapabilities(
+    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint32_t* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
+    for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
+        if (feature & legacy_logger_feature_set) {
+            *hidl_caps |=
+                convertLegacyLoggerFeatureToHidlStaIfaceCapability(feature);
+        }
+    }
+    for (const auto feature :
+         {WIFI_FEATURE_GSCAN, WIFI_FEATURE_LINK_LAYER_STATS,
+          WIFI_FEATURE_RSSI_MONITOR, WIFI_FEATURE_CONTROL_ROAMING,
+          WIFI_FEATURE_IE_WHITELIST, WIFI_FEATURE_SCAN_RAND,
+          WIFI_FEATURE_INFRA_5G, WIFI_FEATURE_HOTSPOT, WIFI_FEATURE_PNO,
+          WIFI_FEATURE_TDLS, WIFI_FEATURE_TDLS_OFFCHANNEL,
+          WIFI_FEATURE_CONFIG_NDO, WIFI_FEATURE_MKEEP_ALIVE}) {
+        if (feature & legacy_feature_set) {
+            *hidl_caps |= convertLegacyFeatureToHidlStaIfaceCapability(feature);
+        }
+    }
+    // There is no flag for this one in the legacy feature set. Adding it to the
+    // set because all the current devices support it.
+    *hidl_caps |= HidlStaIfaceCaps::APF;
+    return true;
+}
+
+bool convertLegacyApfCapabilitiesToHidl(
+    const legacy_hal::PacketFilterCapabilities& legacy_caps,
+    StaApfPacketFilterCapabilities* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    hidl_caps->version = legacy_caps.version;
+    hidl_caps->maxLength = legacy_caps.max_len;
+    return true;
+}
+
+uint8_t convertHidlGscanReportEventFlagToLegacy(
+    StaBackgroundScanBucketEventReportSchemeMask hidl_flag) {
+    using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+    switch (hidl_flag) {
+        case HidlFlag::EACH_SCAN:
+            return REPORT_EVENTS_EACH_SCAN;
+        case HidlFlag::FULL_RESULTS:
+            return REPORT_EVENTS_FULL_RESULTS;
+        case HidlFlag::NO_BATCH:
+            return REPORT_EVENTS_NO_BATCH;
+    };
+    CHECK(false);
+}
+
+StaScanDataFlagMask convertLegacyGscanDataFlagToHidl(uint8_t legacy_flag) {
+    switch (legacy_flag) {
+        case legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED:
+            return StaScanDataFlagMask::INTERRUPTED;
+    };
+    CHECK(false) << "Unknown legacy flag: " << legacy_flag;
+    // To silence the compiler warning about reaching the end of non-void
+    // function.
+    return {};
+}
+
+bool convertLegacyGscanCapabilitiesToHidl(
+    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+    StaBackgroundScanCapabilities* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
+    hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
+    hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
+    hidl_caps->maxReportingThreshold = legacy_caps.max_scan_reporting_threshold;
+    return true;
+}
+
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band) {
+    switch (band) {
+        case WifiBand::BAND_UNSPECIFIED:
+            return legacy_hal::WIFI_BAND_UNSPECIFIED;
+        case WifiBand::BAND_24GHZ:
+            return legacy_hal::WIFI_BAND_BG;
+        case WifiBand::BAND_5GHZ:
+            return legacy_hal::WIFI_BAND_A;
+        case WifiBand::BAND_5GHZ_DFS:
+            return legacy_hal::WIFI_BAND_A_DFS;
+        case WifiBand::BAND_5GHZ_WITH_DFS:
+            return legacy_hal::WIFI_BAND_A_WITH_DFS;
+        case WifiBand::BAND_24GHZ_5GHZ:
+            return legacy_hal::WIFI_BAND_ABG;
+        case WifiBand::BAND_24GHZ_5GHZ_WITH_DFS:
+            return legacy_hal::WIFI_BAND_ABG_WITH_DFS;
+    };
+    CHECK(false);
+}
+
+bool convertHidlGscanParamsToLegacy(
+    const StaBackgroundScanParameters& hidl_scan_params,
+    legacy_hal::wifi_scan_cmd_params* legacy_scan_params) {
+    if (!legacy_scan_params) {
+        return false;
+    }
+    *legacy_scan_params = {};
+    legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
+    legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
+    legacy_scan_params->report_threshold_percent =
+        hidl_scan_params.reportThresholdPercent;
+    legacy_scan_params->report_threshold_num_scans =
+        hidl_scan_params.reportThresholdNumScans;
+    if (hidl_scan_params.buckets.size() > MAX_BUCKETS) {
+        return false;
+    }
+    legacy_scan_params->num_buckets = hidl_scan_params.buckets.size();
+    for (uint32_t bucket_idx = 0; bucket_idx < hidl_scan_params.buckets.size();
+         bucket_idx++) {
+        const StaBackgroundScanBucketParameters& hidl_bucket_spec =
+            hidl_scan_params.buckets[bucket_idx];
+        legacy_hal::wifi_scan_bucket_spec& legacy_bucket_spec =
+            legacy_scan_params->buckets[bucket_idx];
+        if (hidl_bucket_spec.bucketIdx >= MAX_BUCKETS) {
+            return false;
+        }
+        legacy_bucket_spec.bucket = hidl_bucket_spec.bucketIdx;
+        legacy_bucket_spec.band =
+            convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
+        legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
+        legacy_bucket_spec.max_period =
+            hidl_bucket_spec.exponentialMaxPeriodInMs;
+        legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
+        legacy_bucket_spec.step_count = hidl_bucket_spec.exponentialStepCount;
+        legacy_bucket_spec.report_events = 0;
+        using HidlFlag = StaBackgroundScanBucketEventReportSchemeMask;
+        for (const auto flag : {HidlFlag::EACH_SCAN, HidlFlag::FULL_RESULTS,
+                                HidlFlag::NO_BATCH}) {
+            if (hidl_bucket_spec.eventReportScheme &
+                static_cast<std::underlying_type<HidlFlag>::type>(flag)) {
+                legacy_bucket_spec.report_events |=
+                    convertHidlGscanReportEventFlagToLegacy(flag);
+            }
+        }
+        if (hidl_bucket_spec.frequencies.size() > MAX_CHANNELS) {
+            return false;
+        }
+        legacy_bucket_spec.num_channels = hidl_bucket_spec.frequencies.size();
+        for (uint32_t freq_idx = 0;
+             freq_idx < hidl_bucket_spec.frequencies.size(); freq_idx++) {
+            legacy_bucket_spec.channels[freq_idx].channel =
+                hidl_bucket_spec.frequencies[freq_idx];
+        }
+    }
+    return true;
+}
+
+bool convertLegacyIeToHidl(
+    const legacy_hal::wifi_information_element& legacy_ie,
+    WifiInformationElement* hidl_ie) {
+    if (!hidl_ie) {
+        return false;
+    }
+    *hidl_ie = {};
+    hidl_ie->id = legacy_ie.id;
+    hidl_ie->data =
+        std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
+    return true;
+}
+
+bool convertLegacyIeBlobToHidl(const uint8_t* ie_blob, uint32_t ie_blob_len,
+                               std::vector<WifiInformationElement>* hidl_ies) {
+    if (!ie_blob || !hidl_ies) {
+        return false;
+    }
+    *hidl_ies = {};
+    const uint8_t* ies_begin = ie_blob;
+    const uint8_t* ies_end = ie_blob + ie_blob_len;
+    const uint8_t* next_ie = ies_begin;
+    using wifi_ie = legacy_hal::wifi_information_element;
+    constexpr size_t kIeHeaderLen = sizeof(wifi_ie);
+    // Each IE should atleast have the header (i.e |id| & |len| fields).
+    while (next_ie + kIeHeaderLen <= ies_end) {
+        const wifi_ie& legacy_ie = (*reinterpret_cast<const wifi_ie*>(next_ie));
+        uint32_t curr_ie_len = kIeHeaderLen + legacy_ie.len;
+        if (next_ie + curr_ie_len > ies_end) {
+            LOG(ERROR) << "Error parsing IE blob. Next IE: " << (void*)next_ie
+                       << ", Curr IE len: " << curr_ie_len
+                       << ", IEs End: " << (void*)ies_end;
+            break;
+        }
+        WifiInformationElement hidl_ie;
+        if (!convertLegacyIeToHidl(legacy_ie, &hidl_ie)) {
+            LOG(ERROR) << "Error converting IE. Id: " << legacy_ie.id
+                       << ", len: " << legacy_ie.len;
+            break;
+        }
+        hidl_ies->push_back(std::move(hidl_ie));
+        next_ie += curr_ie_len;
+    }
+    // Check if the blob has been fully consumed.
+    if (next_ie != ies_end) {
+        LOG(ERROR) << "Failed to fully parse IE blob. Next IE: "
+                   << (void*)next_ie << ", IEs End: " << (void*)ies_end;
+    }
+    return true;
+}
+
+bool convertLegacyGscanResultToHidl(
+    const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
+    StaScanResult* hidl_scan_result) {
+    if (!hidl_scan_result) {
+        return false;
+    }
+    *hidl_scan_result = {};
+    hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
+    hidl_scan_result->ssid = std::vector<uint8_t>(
+        legacy_scan_result.ssid,
+        legacy_scan_result.ssid + strnlen(legacy_scan_result.ssid,
+                                          sizeof(legacy_scan_result.ssid) - 1));
+    memcpy(hidl_scan_result->bssid.data(), legacy_scan_result.bssid,
+           hidl_scan_result->bssid.size());
+    hidl_scan_result->frequency = legacy_scan_result.channel;
+    hidl_scan_result->rssi = legacy_scan_result.rssi;
+    hidl_scan_result->beaconPeriodInMs = legacy_scan_result.beacon_period;
+    hidl_scan_result->capability = legacy_scan_result.capability;
+    if (has_ie_data) {
+        std::vector<WifiInformationElement> ies;
+        if (!convertLegacyIeBlobToHidl(
+                reinterpret_cast<const uint8_t*>(legacy_scan_result.ie_data),
+                legacy_scan_result.ie_length, &ies)) {
+            return false;
+        }
+        hidl_scan_result->informationElements = std::move(ies);
+    }
+    return true;
+}
+
+bool convertLegacyCachedGscanResultsToHidl(
+    const legacy_hal::wifi_cached_scan_results& legacy_cached_scan_result,
+    StaScanData* hidl_scan_data) {
+    if (!hidl_scan_data) {
+        return false;
+    }
+    *hidl_scan_data = {};
+    hidl_scan_data->flags = 0;
+    for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
+        if (legacy_cached_scan_result.flags & flag) {
+            hidl_scan_data->flags |=
+                static_cast<std::underlying_type<StaScanDataFlagMask>::type>(
+                    convertLegacyGscanDataFlagToHidl(flag));
+        }
+    }
+    hidl_scan_data->bucketsScanned = legacy_cached_scan_result.buckets_scanned;
+
+    CHECK(legacy_cached_scan_result.num_results >= 0 &&
+          legacy_cached_scan_result.num_results <= MAX_AP_CACHE_PER_SCAN);
+    std::vector<StaScanResult> hidl_scan_results;
+    for (int32_t result_idx = 0;
+         result_idx < legacy_cached_scan_result.num_results; result_idx++) {
+        StaScanResult hidl_scan_result;
+        if (!convertLegacyGscanResultToHidl(
+                legacy_cached_scan_result.results[result_idx], false,
+                &hidl_scan_result)) {
+            return false;
+        }
+        hidl_scan_results.push_back(hidl_scan_result);
+    }
+    hidl_scan_data->results = std::move(hidl_scan_results);
+    return true;
+}
+
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
+    const std::vector<legacy_hal::wifi_cached_scan_results>&
+        legacy_cached_scan_results,
+    std::vector<StaScanData>* hidl_scan_datas) {
+    if (!hidl_scan_datas) {
+        return false;
+    }
+    *hidl_scan_datas = {};
+    for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
+        StaScanData hidl_scan_data;
+        if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result,
+                                                   &hidl_scan_data)) {
+            return false;
+        }
+        hidl_scan_datas->push_back(hidl_scan_data);
+    }
+    return true;
+}
+
+WifiDebugTxPacketFate convertLegacyDebugTxPacketFateToHidl(
+    legacy_hal::wifi_tx_packet_fate fate) {
+    switch (fate) {
+        case legacy_hal::TX_PKT_FATE_ACKED:
+            return WifiDebugTxPacketFate::ACKED;
+        case legacy_hal::TX_PKT_FATE_SENT:
+            return WifiDebugTxPacketFate::SENT;
+        case legacy_hal::TX_PKT_FATE_FW_QUEUED:
+            return WifiDebugTxPacketFate::FW_QUEUED;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_INVALID:
+            return WifiDebugTxPacketFate::FW_DROP_INVALID;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_NOBUFS:
+            return WifiDebugTxPacketFate::FW_DROP_NOBUFS;
+        case legacy_hal::TX_PKT_FATE_FW_DROP_OTHER:
+            return WifiDebugTxPacketFate::FW_DROP_OTHER;
+        case legacy_hal::TX_PKT_FATE_DRV_QUEUED:
+            return WifiDebugTxPacketFate::DRV_QUEUED;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_INVALID:
+            return WifiDebugTxPacketFate::DRV_DROP_INVALID;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_NOBUFS:
+            return WifiDebugTxPacketFate::DRV_DROP_NOBUFS;
+        case legacy_hal::TX_PKT_FATE_DRV_DROP_OTHER:
+            return WifiDebugTxPacketFate::DRV_DROP_OTHER;
+    };
+    CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugRxPacketFate convertLegacyDebugRxPacketFateToHidl(
+    legacy_hal::wifi_rx_packet_fate fate) {
+    switch (fate) {
+        case legacy_hal::RX_PKT_FATE_SUCCESS:
+            return WifiDebugRxPacketFate::SUCCESS;
+        case legacy_hal::RX_PKT_FATE_FW_QUEUED:
+            return WifiDebugRxPacketFate::FW_QUEUED;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_FILTER:
+            return WifiDebugRxPacketFate::FW_DROP_FILTER;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_INVALID:
+            return WifiDebugRxPacketFate::FW_DROP_INVALID;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_NOBUFS:
+            return WifiDebugRxPacketFate::FW_DROP_NOBUFS;
+        case legacy_hal::RX_PKT_FATE_FW_DROP_OTHER:
+            return WifiDebugRxPacketFate::FW_DROP_OTHER;
+        case legacy_hal::RX_PKT_FATE_DRV_QUEUED:
+            return WifiDebugRxPacketFate::DRV_QUEUED;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_FILTER:
+            return WifiDebugRxPacketFate::DRV_DROP_FILTER;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_INVALID:
+            return WifiDebugRxPacketFate::DRV_DROP_INVALID;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_NOBUFS:
+            return WifiDebugRxPacketFate::DRV_DROP_NOBUFS;
+        case legacy_hal::RX_PKT_FATE_DRV_DROP_OTHER:
+            return WifiDebugRxPacketFate::DRV_DROP_OTHER;
+    };
+    CHECK(false) << "Unknown legacy fate type: " << fate;
+}
+
+WifiDebugPacketFateFrameType convertLegacyDebugPacketFateFrameTypeToHidl(
+    legacy_hal::frame_type type) {
+    switch (type) {
+        case legacy_hal::FRAME_TYPE_UNKNOWN:
+            return WifiDebugPacketFateFrameType::UNKNOWN;
+        case legacy_hal::FRAME_TYPE_ETHERNET_II:
+            return WifiDebugPacketFateFrameType::ETHERNET_II;
+        case legacy_hal::FRAME_TYPE_80211_MGMT:
+            return WifiDebugPacketFateFrameType::MGMT_80211;
+    };
+    CHECK(false) << "Unknown legacy frame type: " << type;
+}
+
+bool convertLegacyDebugPacketFateFrameToHidl(
+    const legacy_hal::frame_info& legacy_frame,
+    WifiDebugPacketFateFrameInfo* hidl_frame) {
+    if (!hidl_frame) {
+        return false;
+    }
+    *hidl_frame = {};
+    hidl_frame->frameType =
+        convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
+    hidl_frame->frameLen = legacy_frame.frame_len;
+    hidl_frame->driverTimestampUsec = legacy_frame.driver_timestamp_usec;
+    hidl_frame->firmwareTimestampUsec = legacy_frame.firmware_timestamp_usec;
+    const uint8_t* frame_begin = reinterpret_cast<const uint8_t*>(
+        legacy_frame.frame_content.ethernet_ii_bytes);
+    hidl_frame->frameContent =
+        std::vector<uint8_t>(frame_begin, frame_begin + legacy_frame.frame_len);
+    return true;
+}
+
+bool convertLegacyDebugTxPacketFateToHidl(
+    const legacy_hal::wifi_tx_report& legacy_fate,
+    WifiDebugTxPacketFateReport* hidl_fate) {
+    if (!hidl_fate) {
+        return false;
+    }
+    *hidl_fate = {};
+    hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
+    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
+                                                   &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+    std::vector<WifiDebugTxPacketFateReport>* hidl_fates) {
+    if (!hidl_fates) {
+        return false;
+    }
+    *hidl_fates = {};
+    for (const auto& legacy_fate : legacy_fates) {
+        WifiDebugTxPacketFateReport hidl_fate;
+        if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+            return false;
+        }
+        hidl_fates->push_back(hidl_fate);
+    }
+    return true;
+}
+
+bool convertLegacyDebugRxPacketFateToHidl(
+    const legacy_hal::wifi_rx_report& legacy_fate,
+    WifiDebugRxPacketFateReport* hidl_fate) {
+    if (!hidl_fate) {
+        return false;
+    }
+    *hidl_fate = {};
+    hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
+    return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
+                                                   &hidl_fate->frameInfo);
+}
+
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+    std::vector<WifiDebugRxPacketFateReport>* hidl_fates) {
+    if (!hidl_fates) {
+        return false;
+    }
+    *hidl_fates = {};
+    for (const auto& legacy_fate : legacy_fates) {
+        WifiDebugRxPacketFateReport hidl_fate;
+        if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
+            return false;
+        }
+        hidl_fates->push_back(hidl_fate);
+    }
+    return true;
+}
+
+bool convertLegacyLinkLayerStatsToHidl(
+    const legacy_hal::LinkLayerStats& legacy_stats,
+    StaLinkLayerStats* hidl_stats) {
+    if (!hidl_stats) {
+        return false;
+    }
+    *hidl_stats = {};
+    // iface legacy_stats conversion.
+    hidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx;
+    hidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
+    hidl_stats->iface.wmeBePktStats.rxMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu;
+    hidl_stats->iface.wmeBePktStats.txMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu;
+    hidl_stats->iface.wmeBePktStats.lostMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost;
+    hidl_stats->iface.wmeBePktStats.retries =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries;
+    hidl_stats->iface.wmeBkPktStats.rxMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu;
+    hidl_stats->iface.wmeBkPktStats.txMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu;
+    hidl_stats->iface.wmeBkPktStats.lostMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost;
+    hidl_stats->iface.wmeBkPktStats.retries =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries;
+    hidl_stats->iface.wmeViPktStats.rxMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu;
+    hidl_stats->iface.wmeViPktStats.txMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu;
+    hidl_stats->iface.wmeViPktStats.lostMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost;
+    hidl_stats->iface.wmeViPktStats.retries =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries;
+    hidl_stats->iface.wmeVoPktStats.rxMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu;
+    hidl_stats->iface.wmeVoPktStats.txMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu;
+    hidl_stats->iface.wmeVoPktStats.lostMpdu =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost;
+    hidl_stats->iface.wmeVoPktStats.retries =
+        legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
+    // radio legacy_stats conversion.
+    std::vector<StaLinkLayerRadioStats> hidl_radios_stats;
+    for (const auto& legacy_radio_stats : legacy_stats.radios) {
+        StaLinkLayerRadioStats hidl_radio_stats;
+        hidl_radio_stats.onTimeInMs = legacy_radio_stats.stats.on_time;
+        hidl_radio_stats.txTimeInMs = legacy_radio_stats.stats.tx_time;
+        hidl_radio_stats.rxTimeInMs = legacy_radio_stats.stats.rx_time;
+        hidl_radio_stats.onTimeInMsForScan =
+            legacy_radio_stats.stats.on_time_scan;
+        hidl_radio_stats.txTimeInMsPerLevel =
+            legacy_radio_stats.tx_time_per_levels;
+        hidl_radios_stats.push_back(hidl_radio_stats);
+    }
+    hidl_stats->radios = hidl_radios_stats;
+    // Timestamp in the HAL wrapper here since it's not provided in the legacy
+    // HAL API.
+    hidl_stats->timeStampInMs = uptimeMillis();
+    return true;
+}
+
+bool convertLegacyRoamingCapabilitiesToHidl(
+    const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+    StaRoamingCapabilities* hidl_caps) {
+    if (!hidl_caps) {
+        return false;
+    }
+    *hidl_caps = {};
+    hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
+    hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
+    return true;
+}
+
+bool convertHidlRoamingConfigToLegacy(
+    const StaRoamingConfig& hidl_config,
+    legacy_hal::wifi_roaming_config* legacy_config) {
+    if (!legacy_config) {
+        return false;
+    }
+    *legacy_config = {};
+    if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
+        hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
+        return false;
+    }
+    legacy_config->num_blacklist_bssid = hidl_config.bssidBlacklist.size();
+    uint32_t i = 0;
+    for (const auto& bssid : hidl_config.bssidBlacklist) {
+        CHECK(bssid.size() == sizeof(legacy_hal::mac_addr));
+        memcpy(legacy_config->blacklist_bssid[i++], bssid.data(), bssid.size());
+    }
+    legacy_config->num_whitelist_ssid = hidl_config.ssidWhitelist.size();
+    i = 0;
+    for (const auto& ssid : hidl_config.ssidWhitelist) {
+        CHECK(ssid.size() <= sizeof(legacy_hal::ssid_t::ssid_str));
+        legacy_config->whitelist_ssid[i].length = ssid.size();
+        memcpy(legacy_config->whitelist_ssid[i].ssid_str, ssid.data(),
+               ssid.size());
+        i++;
+    }
+    return true;
+}
+
+legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
+    StaRoamingState state) {
+    switch (state) {
+        case StaRoamingState::ENABLED:
+            return legacy_hal::ROAMING_ENABLE;
+        case StaRoamingState::DISABLED:
+            return legacy_hal::ROAMING_DISABLE;
+    };
+    CHECK(false);
+}
+
+legacy_hal::NanMatchAlg convertHidlNanMatchAlgToLegacy(NanMatchAlg type) {
+    switch (type) {
+        case NanMatchAlg::MATCH_ONCE:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_ONCE;
+        case NanMatchAlg::MATCH_CONTINUOUS:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_CONTINUOUS;
+        case NanMatchAlg::MATCH_NEVER:
+            return legacy_hal::NAN_MATCH_ALG_MATCH_NEVER;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanPublishType convertHidlNanPublishTypeToLegacy(
+    NanPublishType type) {
+    switch (type) {
+        case NanPublishType::UNSOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED;
+        case NanPublishType::SOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_SOLICITED;
+        case NanPublishType::UNSOLICITED_SOLICITED:
+            return legacy_hal::NAN_PUBLISH_TYPE_UNSOLICITED_SOLICITED;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanTxType convertHidlNanTxTypeToLegacy(NanTxType type) {
+    switch (type) {
+        case NanTxType::BROADCAST:
+            return legacy_hal::NAN_TX_TYPE_BROADCAST;
+        case NanTxType::UNICAST:
+            return legacy_hal::NAN_TX_TYPE_UNICAST;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanSubscribeType convertHidlNanSubscribeTypeToLegacy(
+    NanSubscribeType type) {
+    switch (type) {
+        case NanSubscribeType::PASSIVE:
+            return legacy_hal::NAN_SUBSCRIBE_TYPE_PASSIVE;
+        case NanSubscribeType::ACTIVE:
+            return legacy_hal::NAN_SUBSCRIBE_TYPE_ACTIVE;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanSRFType convertHidlNanSrfTypeToLegacy(NanSrfType type) {
+    switch (type) {
+        case NanSrfType::BLOOM_FILTER:
+            return legacy_hal::NAN_SRF_ATTR_BLOOM_FILTER;
+        case NanSrfType::PARTIAL_MAC_ADDR:
+            return legacy_hal::NAN_SRF_ATTR_PARTIAL_MAC_ADDR;
+    }
+    CHECK(false);
+}
+
+legacy_hal::NanDataPathChannelCfg convertHidlNanDataPathChannelCfgToLegacy(
+    NanDataPathChannelCfg type) {
+    switch (type) {
+        case NanDataPathChannelCfg::CHANNEL_NOT_REQUESTED:
+            return legacy_hal::NAN_DP_CHANNEL_NOT_REQUESTED;
+        case NanDataPathChannelCfg::REQUEST_CHANNEL_SETUP:
+            return legacy_hal::NAN_DP_REQUEST_CHANNEL_SETUP;
+        case NanDataPathChannelCfg::FORCE_CHANNEL_SETUP:
+            return legacy_hal::NAN_DP_FORCE_CHANNEL_SETUP;
+    }
+    CHECK(false);
+}
+
+NanStatusType convertLegacyNanStatusTypeToHidl(legacy_hal::NanStatusType type) {
+    switch (type) {
+        case legacy_hal::NAN_STATUS_SUCCESS:
+            return NanStatusType::SUCCESS;
+        case legacy_hal::NAN_STATUS_INTERNAL_FAILURE:
+            return NanStatusType::INTERNAL_FAILURE;
+        case legacy_hal::NAN_STATUS_PROTOCOL_FAILURE:
+            return NanStatusType::PROTOCOL_FAILURE;
+        case legacy_hal::NAN_STATUS_INVALID_PUBLISH_SUBSCRIBE_ID:
+            return NanStatusType::INVALID_SESSION_ID;
+        case legacy_hal::NAN_STATUS_NO_RESOURCE_AVAILABLE:
+            return NanStatusType::NO_RESOURCES_AVAILABLE;
+        case legacy_hal::NAN_STATUS_INVALID_PARAM:
+            return NanStatusType::INVALID_ARGS;
+        case legacy_hal::NAN_STATUS_INVALID_REQUESTOR_INSTANCE_ID:
+            return NanStatusType::INVALID_PEER_ID;
+        case legacy_hal::NAN_STATUS_INVALID_NDP_ID:
+            return NanStatusType::INVALID_NDP_ID;
+        case legacy_hal::NAN_STATUS_NAN_NOT_ALLOWED:
+            return NanStatusType::NAN_NOT_ALLOWED;
+        case legacy_hal::NAN_STATUS_NO_OTA_ACK:
+            return NanStatusType::NO_OTA_ACK;
+        case legacy_hal::NAN_STATUS_ALREADY_ENABLED:
+            return NanStatusType::ALREADY_ENABLED;
+        case legacy_hal::NAN_STATUS_FOLLOWUP_QUEUE_FULL:
+            return NanStatusType::FOLLOWUP_TX_QUEUE_FULL;
+        case legacy_hal::NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED:
+            return NanStatusType::UNSUPPORTED_CONCURRENCY_NAN_DISABLED;
+    }
+    CHECK(false);
+}
+
+void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
+                            size_t max_len, WifiNanStatus* wifiNanStatus) {
+    wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(type);
+    wifiNanStatus->description = safeConvertChar(str, max_len);
+}
+
+bool convertHidlNanEnableRequestToLegacy(
+    const NanEnableRequest& hidl_request,
+    legacy_hal::NanEnableRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanEnableRequestToLegacy: null legacy_request";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->config_2dot4g_support = 1;
+    legacy_request->support_2dot4g_val =
+        hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_support_5g = 1;
+    legacy_request->support_5g_val =
+        hidl_request.operateInBand[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_hop_count_limit = 1;
+    legacy_request->hop_count_limit_val = hidl_request.hopCountMax;
+    legacy_request->master_pref = hidl_request.configParams.masterPref;
+    legacy_request->discovery_indication_cfg = 0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.configParams.disableDiscoveryAddressChangeIndication ? 0x1
+                                                                          : 0x0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.configParams.disableStartedClusterIndication ? 0x2 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.configParams.disableJoinedClusterIndication ? 0x4 : 0x0;
+    legacy_request->config_sid_beacon = 1;
+    if (hidl_request.configParams.numberOfPublishServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+                      "numberOfPublishServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->sid_beacon_val =
+        (hidl_request.configParams.includePublishServiceIdsInBeacon ? 0x1
+                                                                    : 0x0) |
+        (hidl_request.configParams.numberOfPublishServiceIdsInBeacon << 1);
+    legacy_request->config_subscribe_sid_beacon = 1;
+    if (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+                      "numberOfSubscribeServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->subscribe_sid_beacon_val =
+        (hidl_request.configParams.includeSubscribeServiceIdsInBeacon ? 0x1
+                                                                      : 0x0) |
+        (hidl_request.configParams.numberOfSubscribeServiceIdsInBeacon << 1);
+    legacy_request->config_rssi_window_size = 1;
+    legacy_request->rssi_window_size_val =
+        hidl_request.configParams.rssiWindowSize;
+    legacy_request->config_disc_mac_addr_randomization = 1;
+    legacy_request->disc_mac_addr_rand_interval_sec =
+        hidl_request.configParams.macAddressRandomizationIntervalSec;
+    legacy_request->config_2dot4g_rssi_close = 1;
+    if (hidl_request.configParams.bandSpecificConfig.size() != 2) {
+        LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: "
+                      "bandSpecificConfig.size() != 2";
+        return false;
+    }
+    legacy_request->rssi_close_2dot4g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .rssiClose;
+    legacy_request->config_2dot4g_rssi_middle = 1;
+    legacy_request->rssi_middle_2dot4g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .rssiMiddle;
+    legacy_request->config_2dot4g_rssi_proximity = 1;
+    legacy_request->rssi_proximity_2dot4g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .rssiCloseProximity;
+    legacy_request->config_scan_params = 1;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .scanPeriodSec;
+    legacy_request->config_dw.config_2dot4g_dw_band =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_2dot4g_interval_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .discoveryWindowIntervalVal;
+    legacy_request->config_5g_rssi_close = 1;
+    legacy_request->rssi_close_5g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .rssiClose;
+    legacy_request->config_5g_rssi_middle = 1;
+    legacy_request->rssi_middle_5g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .rssiMiddle;
+    legacy_request->config_5g_rssi_close_proximity = 1;
+    legacy_request->rssi_close_proximity_5g_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .rssiCloseProximity;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .scanPeriodSec;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .scanPeriodSec;
+    legacy_request->config_dw.config_5g_dw_band =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_5g_interval_val =
+        hidl_request.configParams
+            .bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .discoveryWindowIntervalVal;
+    if (hidl_request.debugConfigs.validClusterIdVals) {
+        legacy_request->cluster_low =
+            hidl_request.debugConfigs.clusterIdBottomRangeVal;
+        legacy_request->cluster_high =
+            hidl_request.debugConfigs.clusterIdTopRangeVal;
+    } else {  // need 'else' since not configurable in legacy HAL
+        legacy_request->cluster_low = 0x0000;
+        legacy_request->cluster_high = 0xFFFF;
+    }
+    legacy_request->config_intf_addr =
+        hidl_request.debugConfigs.validIntfAddrVal;
+    memcpy(legacy_request->intf_addr_val,
+           hidl_request.debugConfigs.intfAddrVal.data(), 6);
+    legacy_request->config_oui = hidl_request.debugConfigs.validOuiVal;
+    legacy_request->oui_val = hidl_request.debugConfigs.ouiVal;
+    legacy_request->config_random_factor_force =
+        hidl_request.debugConfigs.validRandomFactorForceVal;
+    legacy_request->random_factor_force_val =
+        hidl_request.debugConfigs.randomFactorForceVal;
+    legacy_request->config_hop_count_force =
+        hidl_request.debugConfigs.validHopCountForceVal;
+    legacy_request->hop_count_force_val =
+        hidl_request.debugConfigs.hopCountForceVal;
+    legacy_request->config_24g_channel =
+        hidl_request.debugConfigs.validDiscoveryChannelVal;
+    legacy_request->channel_24g_val =
+        hidl_request.debugConfigs
+            .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_channel =
+        hidl_request.debugConfigs.validDiscoveryChannelVal;
+    legacy_request->channel_5g_val =
+        hidl_request.debugConfigs
+            .discoveryChannelMhzVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_2dot4g_beacons =
+        hidl_request.debugConfigs.validUseBeaconsInBandVal;
+    legacy_request->beacon_2dot4g_val =
+        hidl_request.debugConfigs
+            .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_beacons =
+        hidl_request.debugConfigs.validUseBeaconsInBandVal;
+    legacy_request->beacon_5g_val =
+        hidl_request.debugConfigs
+            .useBeaconsInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+    legacy_request->config_2dot4g_sdf =
+        hidl_request.debugConfigs.validUseSdfInBandVal;
+    legacy_request->sdf_2dot4g_val =
+        hidl_request.debugConfigs
+            .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_24GHZ];
+    legacy_request->config_5g_sdf =
+        hidl_request.debugConfigs.validUseSdfInBandVal;
+    legacy_request->sdf_5g_val =
+        hidl_request.debugConfigs
+            .useSdfInBandVal[(size_t)NanBandIndex::NAN_BAND_5GHZ];
+
+    return true;
+}
+
+bool convertHidlNanEnableRequest_1_2ToLegacy(
+    const NanEnableRequest& hidl_request1,
+    const NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanEnableRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanEnableRequest_1_2ToLegacy: null legacy_request";
+        return false;
+    }
+
+    *legacy_request = {};
+    if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
+        return false;
+    }
+
+    legacy_request->config_discovery_beacon_int = 1;
+    legacy_request->discovery_beacon_interval =
+        hidl_request2.discoveryBeaconIntervalMs;
+    legacy_request->config_nss = 1;
+    legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+    legacy_request->config_dw_early_termination = 1;
+    legacy_request->enable_dw_termination =
+        hidl_request2.enableDiscoveryWindowEarlyTermination;
+    legacy_request->config_enable_ranging = 1;
+    legacy_request->enable_ranging = hidl_request2.enableRanging;
+
+    return true;
+}
+
+bool convertHidlNanPublishRequestToLegacy(
+    const NanPublishRequest& hidl_request,
+    legacy_hal::NanPublishRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanPublishRequestToLegacy: null legacy_request";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
+    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
+    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
+    legacy_request->publish_count = hidl_request.baseConfigs.discoveryCount;
+    legacy_request->service_name_len =
+        hidl_request.baseConfigs.serviceName.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: service_name_len "
+                      "too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name,
+           hidl_request.baseConfigs.serviceName.data(),
+           legacy_request->service_name_len);
+    legacy_request->publish_match_indicator = convertHidlNanMatchAlgToLegacy(
+        hidl_request.baseConfigs.discoveryMatchIndicator);
+    legacy_request->service_specific_info_len =
+        hidl_request.baseConfigs.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len >
+        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info,
+           hidl_request.baseConfigs.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+        hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len >
+        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->rx_match_filter_len =
+        hidl_request.baseConfigs.rxMatchFilter.size();
+    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "rx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->rx_match_filter,
+           hidl_request.baseConfigs.rxMatchFilter.data(),
+           legacy_request->rx_match_filter_len);
+    legacy_request->tx_match_filter_len =
+        hidl_request.baseConfigs.txMatchFilter.size();
+    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                      "tx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->tx_match_filter,
+           hidl_request.baseConfigs.txMatchFilter.data(),
+           legacy_request->tx_match_filter_len);
+    legacy_request->rssi_threshold_flag =
+        hidl_request.baseConfigs.useRssiThreshold;
+    legacy_request->recv_indication_cfg = 0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
+                                                                       : 0x0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+    legacy_request->recv_indication_cfg |= 0x8;
+    legacy_request->cipher_type =
+        (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
+    if (hidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+            hidl_request.baseConfigs.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len !=
+            NAN_PMK_INFO_LEN) {
+            LOG(ERROR)
+                << "convertHidlNanPublishRequestToLegacy: invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               hidl_request.baseConfigs.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+            hidl_request.baseConfigs.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.baseConfigs.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->sdea_params.security_cfg =
+        (hidl_request.baseConfigs.securityConfig.securityType !=
+         NanDataPathSecurityType::OPEN)
+            ? legacy_hal::NAN_DP_CONFIG_SECURITY
+            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->sdea_params.ranging_state =
+        hidl_request.baseConfigs.rangingRequired
+            ? legacy_hal::NAN_RANGING_ENABLE
+            : legacy_hal::NAN_RANGING_DISABLE;
+    legacy_request->ranging_cfg.ranging_interval_msec =
+        hidl_request.baseConfigs.rangingIntervalMsec;
+    legacy_request->ranging_cfg.config_ranging_indications =
+        hidl_request.baseConfigs.configRangingIndications;
+    legacy_request->ranging_cfg.distance_ingress_mm =
+        hidl_request.baseConfigs.distanceIngressCm * 10;
+    legacy_request->ranging_cfg.distance_egress_mm =
+        hidl_request.baseConfigs.distanceEgressCm * 10;
+    legacy_request->ranging_auto_response =
+        hidl_request.baseConfigs.rangingRequired
+            ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+            : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+    legacy_request->sdea_params.range_report =
+        legacy_hal::NAN_DISABLE_RANGE_REPORT;
+    legacy_request->publish_type =
+        convertHidlNanPublishTypeToLegacy(hidl_request.publishType);
+    legacy_request->tx_type = convertHidlNanTxTypeToLegacy(hidl_request.txType);
+    legacy_request->service_responder_policy =
+        hidl_request.autoAcceptDataPathRequests
+            ? legacy_hal::NAN_SERVICE_ACCEPT_POLICY_ALL
+            : legacy_hal::NAN_SERVICE_ACCEPT_POLICY_NONE;
+
+    return true;
+}
+
+bool convertHidlNanSubscribeRequestToLegacy(
+    const NanSubscribeRequest& hidl_request,
+    legacy_hal::NanSubscribeRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
+    legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
+    legacy_request->period = hidl_request.baseConfigs.discoveryWindowPeriod;
+    legacy_request->subscribe_count = hidl_request.baseConfigs.discoveryCount;
+    legacy_request->service_name_len =
+        hidl_request.baseConfigs.serviceName.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name,
+           hidl_request.baseConfigs.serviceName.data(),
+           legacy_request->service_name_len);
+    legacy_request->subscribe_match_indicator = convertHidlNanMatchAlgToLegacy(
+        hidl_request.baseConfigs.discoveryMatchIndicator);
+    legacy_request->service_specific_info_len =
+        hidl_request.baseConfigs.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len >
+        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info,
+           hidl_request.baseConfigs.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+        hidl_request.baseConfigs.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len >
+        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           hidl_request.baseConfigs.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->rx_match_filter_len =
+        hidl_request.baseConfigs.rxMatchFilter.size();
+    if (legacy_request->rx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "rx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->rx_match_filter,
+           hidl_request.baseConfigs.rxMatchFilter.data(),
+           legacy_request->rx_match_filter_len);
+    legacy_request->tx_match_filter_len =
+        hidl_request.baseConfigs.txMatchFilter.size();
+    if (legacy_request->tx_match_filter_len > NAN_MAX_MATCH_FILTER_LEN) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "tx_match_filter_len too large";
+        return false;
+    }
+    memcpy(legacy_request->tx_match_filter,
+           hidl_request.baseConfigs.txMatchFilter.data(),
+           legacy_request->tx_match_filter_len);
+    legacy_request->rssi_threshold_flag =
+        hidl_request.baseConfigs.useRssiThreshold;
+    legacy_request->recv_indication_cfg = 0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableDiscoveryTerminationIndication ? 0x1
+                                                                       : 0x0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableMatchExpirationIndication ? 0x2 : 0x0;
+    legacy_request->recv_indication_cfg |=
+        hidl_request.baseConfigs.disableFollowupReceivedIndication ? 0x4 : 0x0;
+    legacy_request->cipher_type =
+        (unsigned int)hidl_request.baseConfigs.securityConfig.cipherType;
+    if (hidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+            hidl_request.baseConfigs.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len !=
+            NAN_PMK_INFO_LEN) {
+            LOG(ERROR)
+                << "convertHidlNanSubscribeRequestToLegacy: invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               hidl_request.baseConfigs.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.baseConfigs.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+            hidl_request.baseConfigs.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.baseConfigs.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->sdea_params.security_cfg =
+        (hidl_request.baseConfigs.securityConfig.securityType !=
+         NanDataPathSecurityType::OPEN)
+            ? legacy_hal::NAN_DP_CONFIG_SECURITY
+            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->sdea_params.ranging_state =
+        hidl_request.baseConfigs.rangingRequired
+            ? legacy_hal::NAN_RANGING_ENABLE
+            : legacy_hal::NAN_RANGING_DISABLE;
+    legacy_request->ranging_cfg.ranging_interval_msec =
+        hidl_request.baseConfigs.rangingIntervalMsec;
+    legacy_request->ranging_cfg.config_ranging_indications =
+        hidl_request.baseConfigs.configRangingIndications;
+    legacy_request->ranging_cfg.distance_ingress_mm =
+        hidl_request.baseConfigs.distanceIngressCm * 10;
+    legacy_request->ranging_cfg.distance_egress_mm =
+        hidl_request.baseConfigs.distanceEgressCm * 10;
+    legacy_request->ranging_auto_response =
+        hidl_request.baseConfigs.rangingRequired
+            ? legacy_hal::NAN_RANGING_AUTO_RESPONSE_ENABLE
+            : legacy_hal::NAN_RANGING_AUTO_RESPONSE_DISABLE;
+    legacy_request->sdea_params.range_report =
+        legacy_hal::NAN_DISABLE_RANGE_REPORT;
+    legacy_request->subscribe_type =
+        convertHidlNanSubscribeTypeToLegacy(hidl_request.subscribeType);
+    legacy_request->serviceResponseFilter =
+        convertHidlNanSrfTypeToLegacy(hidl_request.srfType);
+    legacy_request->serviceResponseInclude =
+        hidl_request.srfRespondIfInAddressSet
+            ? legacy_hal::NAN_SRF_INCLUDE_RESPOND
+            : legacy_hal::NAN_SRF_INCLUDE_DO_NOT_RESPOND;
+    legacy_request->useServiceResponseFilter =
+        hidl_request.shouldUseSrf ? legacy_hal::NAN_USE_SRF
+                                  : legacy_hal::NAN_DO_NOT_USE_SRF;
+    legacy_request->ssiRequiredForMatchIndication =
+        hidl_request.isSsiRequiredForMatch
+            ? legacy_hal::NAN_SSI_REQUIRED_IN_MATCH_IND
+            : legacy_hal::NAN_SSI_NOT_REQUIRED_IN_MATCH_IND;
+    legacy_request->num_intf_addr_present = hidl_request.intfAddr.size();
+    if (legacy_request->num_intf_addr_present > NAN_MAX_SUBSCRIBE_MAX_ADDRESS) {
+        LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: "
+                      "num_intf_addr_present - too many";
+        return false;
+    }
+    for (int i = 0; i < legacy_request->num_intf_addr_present; i++) {
+        memcpy(legacy_request->intf_addr[i], hidl_request.intfAddr[i].data(),
+               6);
+    }
+
+    return true;
+}
+
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+    const NanTransmitFollowupRequest& hidl_request,
+    legacy_hal::NanTransmitFollowupRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
+    legacy_request->requestor_instance_id = hidl_request.peerId;
+    memcpy(legacy_request->addr, hidl_request.addr.data(), 6);
+    legacy_request->priority = hidl_request.isHighPriority
+                                   ? legacy_hal::NAN_TX_PRIORITY_HIGH
+                                   : legacy_hal::NAN_TX_PRIORITY_NORMAL;
+    legacy_request->dw_or_faw = hidl_request.shouldUseDiscoveryWindow
+                                    ? legacy_hal::NAN_TRANSMIT_IN_DW
+                                    : legacy_hal::NAN_TRANSMIT_IN_FAW;
+    legacy_request->service_specific_info_len =
+        hidl_request.serviceSpecificInfo.size();
+    if (legacy_request->service_specific_info_len >
+        NAN_MAX_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+                      "service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_specific_info,
+           hidl_request.serviceSpecificInfo.data(),
+           legacy_request->service_specific_info_len);
+    legacy_request->sdea_service_specific_info_len =
+        hidl_request.extendedServiceSpecificInfo.size();
+    if (legacy_request->sdea_service_specific_info_len >
+        NAN_MAX_SDEA_SERVICE_SPECIFIC_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: "
+                      "sdea_service_specific_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->sdea_service_specific_info,
+           hidl_request.extendedServiceSpecificInfo.data(),
+           legacy_request->sdea_service_specific_info_len);
+    legacy_request->recv_indication_cfg =
+        hidl_request.disableFollowupResultIndication ? 0x1 : 0x0;
+
+    return true;
+}
+
+bool convertHidlNanConfigRequestToLegacy(
+    const NanConfigRequest& hidl_request,
+    legacy_hal::NanConfigRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown
+    // defaults
+    legacy_request->master_pref = hidl_request.masterPref;
+    legacy_request->discovery_indication_cfg = 0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.disableDiscoveryAddressChangeIndication ? 0x1 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.disableStartedClusterIndication ? 0x2 : 0x0;
+    legacy_request->discovery_indication_cfg |=
+        hidl_request.disableJoinedClusterIndication ? 0x4 : 0x0;
+    legacy_request->config_sid_beacon = 1;
+    if (hidl_request.numberOfPublishServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
+                      "numberOfPublishServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->sid_beacon =
+        (hidl_request.includePublishServiceIdsInBeacon ? 0x1 : 0x0) |
+        (hidl_request.numberOfPublishServiceIdsInBeacon << 1);
+    legacy_request->config_subscribe_sid_beacon = 1;
+    if (hidl_request.numberOfSubscribeServiceIdsInBeacon > 127) {
+        LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: "
+                      "numberOfSubscribeServiceIdsInBeacon > 127";
+        return false;
+    }
+    legacy_request->subscribe_sid_beacon_val =
+        (hidl_request.includeSubscribeServiceIdsInBeacon ? 0x1 : 0x0) |
+        (hidl_request.numberOfSubscribeServiceIdsInBeacon << 1);
+    legacy_request->config_rssi_window_size = 1;
+    legacy_request->rssi_window_size_val = hidl_request.rssiWindowSize;
+    legacy_request->config_disc_mac_addr_randomization = 1;
+    legacy_request->disc_mac_addr_rand_interval_sec =
+        hidl_request.macAddressRandomizationIntervalSec;
+    /* TODO : missing
+    legacy_request->config_2dot4g_rssi_close = 1;
+    legacy_request->rssi_close_2dot4g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiClose;
+    legacy_request->config_2dot4g_rssi_middle = 1;
+    legacy_request->rssi_middle_2dot4g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiMiddle;
+    legacy_request->config_2dot4g_rssi_proximity = 1;
+    legacy_request->rssi_proximity_2dot4g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_24GHZ].rssiCloseProximity;
+    */
+    legacy_request->config_scan_params = 1;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_24G_BAND] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_24G_BAND] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .scanPeriodSec;
+    legacy_request->config_dw.config_2dot4g_dw_band =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_2dot4g_interval_val =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_24GHZ]
+            .discoveryWindowIntervalVal;
+    /* TODO: missing
+    legacy_request->config_5g_rssi_close = 1;
+    legacy_request->rssi_close_5g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiClose;
+    legacy_request->config_5g_rssi_middle = 1;
+    legacy_request->rssi_middle_5g_val =
+          hidl_request.bandSpecificConfig[
+              (size_t) NanBandIndex::NAN_BAND_5GHZ].rssiMiddle;
+    */
+    legacy_request->config_5g_rssi_close_proximity = 1;
+    legacy_request->rssi_close_proximity_5g_val =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .rssiCloseProximity;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_LOW] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .scanPeriodSec;
+    legacy_request->scan_params_val
+        .dwell_time[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .dwellTimeMs;
+    legacy_request->scan_params_val
+        .scan_period[legacy_hal::NAN_CHANNEL_5G_BAND_HIGH] =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .scanPeriodSec;
+    legacy_request->config_dw.config_5g_dw_band =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .validDiscoveryWindowIntervalVal;
+    legacy_request->config_dw.dw_5g_interval_val =
+        hidl_request.bandSpecificConfig[(size_t)NanBandIndex::NAN_BAND_5GHZ]
+            .discoveryWindowIntervalVal;
+
+    return true;
+}
+
+bool convertHidlNanConfigRequest_1_2ToLegacy(
+    const NanConfigRequest& hidl_request1,
+    const NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanConfigRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanConfigRequest_1_2ToLegacy: legacy_request "
+                      "is null";
+        return false;
+    }
+
+    *legacy_request = {};
+    if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
+        return false;
+    }
+
+    legacy_request->config_discovery_beacon_int = 1;
+    legacy_request->discovery_beacon_interval =
+        hidl_request2.discoveryBeaconIntervalMs;
+    legacy_request->config_nss = 1;
+    legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+    legacy_request->config_dw_early_termination = 1;
+    legacy_request->enable_dw_termination =
+        hidl_request2.enableDiscoveryWindowEarlyTermination;
+    legacy_request->config_enable_ranging = 1;
+    legacy_request->enable_ranging = hidl_request2.enableRanging;
+
+    return true;
+}
+
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+    const NanInitiateDataPathRequest& hidl_request,
+    legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->requestor_instance_id = hidl_request.peerId;
+    memcpy(legacy_request->peer_disc_mac_addr,
+           hidl_request.peerDiscMacAddr.data(), 6);
+    legacy_request->channel_request_type =
+        convertHidlNanDataPathChannelCfgToLegacy(
+            hidl_request.channelRequestType);
+    legacy_request->channel = hidl_request.channel;
+    strcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str());
+    legacy_request->ndp_cfg.security_cfg =
+        (hidl_request.securityConfig.securityType !=
+         NanDataPathSecurityType::OPEN)
+            ? legacy_hal::NAN_DP_CONFIG_SECURITY
+            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "ndp_app_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+           legacy_request->app_info.ndp_app_info_len);
+    legacy_request->cipher_type =
+        (unsigned int)hidl_request.securityConfig.cipherType;
+    if (hidl_request.securityConfig.securityType ==
+        NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+            hidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len !=
+            NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               hidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+            hidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name,
+           hidl_request.serviceNameOutOfBand.data(),
+           legacy_request->service_name_len);
+
+    return true;
+}
+
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+    const NanRespondToDataPathIndicationRequest& hidl_request,
+    legacy_hal::NanDataPathIndicationResponse* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "legacy_request is null";
+        return false;
+    }
+    *legacy_request = {};
+
+    legacy_request->rsp_code = hidl_request.acceptRequest
+                                   ? legacy_hal::NAN_DP_REQUEST_ACCEPT
+                                   : legacy_hal::NAN_DP_REQUEST_REJECT;
+    legacy_request->ndp_instance_id = hidl_request.ndpInstanceId;
+    strcpy(legacy_request->ndp_iface, hidl_request.ifaceName.c_str());
+    legacy_request->ndp_cfg.security_cfg =
+        (hidl_request.securityConfig.securityType !=
+         NanDataPathSecurityType::OPEN)
+            ? legacy_hal::NAN_DP_CONFIG_SECURITY
+            : legacy_hal::NAN_DP_CONFIG_NO_SECURITY;
+    legacy_request->app_info.ndp_app_info_len = hidl_request.appInfo.size();
+    if (legacy_request->app_info.ndp_app_info_len > NAN_DP_MAX_APP_INFO_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "ndp_app_info_len too large";
+        return false;
+    }
+    memcpy(legacy_request->app_info.ndp_app_info, hidl_request.appInfo.data(),
+           legacy_request->app_info.ndp_app_info_len);
+    legacy_request->cipher_type =
+        (unsigned int)hidl_request.securityConfig.cipherType;
+    if (hidl_request.securityConfig.securityType ==
+        NanDataPathSecurityType::PMK) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PMK;
+        legacy_request->key_info.body.pmk_info.pmk_len =
+            hidl_request.securityConfig.pmk.size();
+        if (legacy_request->key_info.body.pmk_info.pmk_len !=
+            NAN_PMK_INFO_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                          "invalid pmk_len";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.pmk_info.pmk,
+               hidl_request.securityConfig.pmk.data(),
+               legacy_request->key_info.body.pmk_info.pmk_len);
+    }
+    if (hidl_request.securityConfig.securityType ==
+        NanDataPathSecurityType::PASSPHRASE) {
+        legacy_request->key_info.key_type =
+            legacy_hal::NAN_SECURITY_KEY_INPUT_PASSPHRASE;
+        legacy_request->key_info.body.passphrase_info.passphrase_len =
+            hidl_request.securityConfig.passphrase.size();
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len <
+            NAN_SECURITY_MIN_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                          "passphrase_len too small";
+            return false;
+        }
+        if (legacy_request->key_info.body.passphrase_info.passphrase_len >
+            NAN_SECURITY_MAX_PASSPHRASE_LEN) {
+            LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                          "passphrase_len too large";
+            return false;
+        }
+        memcpy(legacy_request->key_info.body.passphrase_info.passphrase,
+               hidl_request.securityConfig.passphrase.data(),
+               legacy_request->key_info.body.passphrase_info.passphrase_len);
+    }
+    legacy_request->service_name_len = hidl_request.serviceNameOutOfBand.size();
+    if (legacy_request->service_name_len > NAN_MAX_SERVICE_NAME_LEN) {
+        LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: "
+                      "service_name_len too large";
+        return false;
+    }
+    memcpy(legacy_request->service_name,
+           hidl_request.serviceNameOutOfBand.data(),
+           legacy_request->service_name_len);
+
+    return true;
+}
+
+bool convertLegacyNanResponseHeaderToHidl(
+    const legacy_hal::NanResponseMsg& legacy_response,
+    WifiNanStatus* wifiNanStatus) {
+    if (!wifiNanStatus) {
+        LOG(ERROR)
+            << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
+        return false;
+    }
+    *wifiNanStatus = {};
+
+    convertToWifiNanStatus(legacy_response.status, legacy_response.nan_error,
+                           sizeof(legacy_response.nan_error), wifiNanStatus);
+    return true;
+}
+
+bool convertLegacyNanCapabilitiesResponseToHidl(
+    const legacy_hal::NanCapabilities& legacy_response,
+    NanCapabilities* hidl_response) {
+    if (!hidl_response) {
+        LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: "
+                      "hidl_response is null";
+        return false;
+    }
+    *hidl_response = {};
+
+    hidl_response->maxConcurrentClusters =
+        legacy_response.max_concurrent_nan_clusters;
+    hidl_response->maxPublishes = legacy_response.max_publishes;
+    hidl_response->maxSubscribes = legacy_response.max_subscribes;
+    hidl_response->maxServiceNameLen = legacy_response.max_service_name_len;
+    hidl_response->maxMatchFilterLen = legacy_response.max_match_filter_len;
+    hidl_response->maxTotalMatchFilterLen =
+        legacy_response.max_total_match_filter_len;
+    hidl_response->maxServiceSpecificInfoLen =
+        legacy_response.max_service_specific_info_len;
+    hidl_response->maxExtendedServiceSpecificInfoLen =
+        legacy_response.max_sdea_service_specific_info_len;
+    hidl_response->maxNdiInterfaces = legacy_response.max_ndi_interfaces;
+    hidl_response->maxNdpSessions = legacy_response.max_ndp_sessions;
+    hidl_response->maxAppInfoLen = legacy_response.max_app_info_len;
+    hidl_response->maxQueuedTransmitFollowupMsgs =
+        legacy_response.max_queued_transmit_followup_msgs;
+    hidl_response->maxSubscribeInterfaceAddresses =
+        legacy_response.max_subscribe_address;
+    hidl_response->supportedCipherSuites =
+        legacy_response.cipher_suites_supported;
+
+    return true;
+}
+
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+                                    NanMatchInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+    hidl_ind->peerId = legacy_ind.requestor_instance_id;
+    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
+    hidl_ind->serviceSpecificInfo =
+        std::vector<uint8_t>(legacy_ind.service_specific_info,
+                             legacy_ind.service_specific_info +
+                                 legacy_ind.service_specific_info_len);
+    hidl_ind->extendedServiceSpecificInfo =
+        std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
+                             legacy_ind.sdea_service_specific_info +
+                                 legacy_ind.sdea_service_specific_info_len);
+    hidl_ind->matchFilter = std::vector<uint8_t>(
+        legacy_ind.sdf_match_filter,
+        legacy_ind.sdf_match_filter + legacy_ind.sdf_match_filter_len);
+    hidl_ind->matchOccuredInBeaconFlag = legacy_ind.match_occured_flag == 1;
+    hidl_ind->outOfResourceFlag = legacy_ind.out_of_resource_flag == 1;
+    hidl_ind->rssiValue = legacy_ind.rssi_value;
+    hidl_ind->peerCipherType = (NanCipherSuiteType)legacy_ind.peer_cipher_type;
+    hidl_ind->peerRequiresSecurityEnabledInNdp =
+        legacy_ind.peer_sdea_params.security_cfg ==
+        legacy_hal::NAN_DP_CONFIG_SECURITY;
+    hidl_ind->peerRequiresRanging = legacy_ind.peer_sdea_params.ranging_state ==
+                                    legacy_hal::NAN_RANGING_ENABLE;
+    hidl_ind->rangingMeasurementInCm =
+        legacy_ind.range_info.range_measurement_mm / 10;
+    hidl_ind->rangingIndicationType = legacy_ind.range_info.ranging_event_type;
+
+    return true;
+}
+
+bool convertLegacyNanFollowupIndToHidl(
+    const legacy_hal::NanFollowupInd& legacy_ind,
+    NanFollowupReceivedInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
+    hidl_ind->peerId = legacy_ind.requestor_instance_id;
+    hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
+    hidl_ind->receivedInFaw = legacy_ind.dw_or_faw == 1;
+    hidl_ind->serviceSpecificInfo =
+        std::vector<uint8_t>(legacy_ind.service_specific_info,
+                             legacy_ind.service_specific_info +
+                                 legacy_ind.service_specific_info_len);
+    hidl_ind->extendedServiceSpecificInfo =
+        std::vector<uint8_t>(legacy_ind.sdea_service_specific_info,
+                             legacy_ind.sdea_service_specific_info +
+                                 legacy_ind.sdea_service_specific_info_len);
+
+    return true;
+}
+
+bool convertLegacyNanDataPathRequestIndToHidl(
+    const legacy_hal::NanDataPathRequestInd& legacy_ind,
+    NanDataPathRequestInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR)
+            << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
+    hidl_ind->peerDiscMacAddr =
+        hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
+    hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
+    hidl_ind->securityRequired =
+        legacy_ind.ndp_cfg.security_cfg == legacy_hal::NAN_DP_CONFIG_SECURITY;
+    hidl_ind->appInfo =
+        std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
+                             legacy_ind.app_info.ndp_app_info +
+                                 legacy_ind.app_info.ndp_app_info_len);
+
+    return true;
+}
+
+bool convertLegacyNdpChannelInfoToHidl(
+    const legacy_hal::NanChannelInfo& legacy_struct,
+    NanDataPathChannelInfo* hidl_struct) {
+    if (!hidl_struct) {
+        LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
+        return false;
+    }
+    *hidl_struct = {};
+
+    hidl_struct->channelFreq = legacy_struct.channel;
+    hidl_struct->channelBandwidth = legacy_struct.bandwidth;
+    hidl_struct->numSpatialStreams = legacy_struct.nss;
+
+    return true;
+}
+
+bool convertLegacyNanDataPathConfirmIndToHidl(
+    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+    NanDataPathConfirmInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR)
+            << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
+    hidl_ind->V1_0.dataPathSetupSuccess =
+        legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
+    hidl_ind->V1_0.peerNdiMacAddr =
+        hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
+    hidl_ind->V1_0.appInfo =
+        std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
+                             legacy_ind.app_info.ndp_app_info +
+                                 legacy_ind.app_info.ndp_app_info_len);
+    hidl_ind->V1_0.status.status =
+        convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
+    hidl_ind->V1_0.status.description = "";  // TODO: b/34059183
+
+    std::vector<NanDataPathChannelInfo> channelInfo;
+    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+        NanDataPathChannelInfo hidl_struct;
+        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
+                                               &hidl_struct)) {
+            return false;
+        }
+        channelInfo.push_back(hidl_struct);
+    }
+    hidl_ind->channelInfo = channelInfo;
+
+    return true;
+}
+
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+    const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+    NanDataPathScheduleUpdateInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
+                      "hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->peerDiscoveryAddress =
+        hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
+    std::vector<NanDataPathChannelInfo> channelInfo;
+    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+        NanDataPathChannelInfo hidl_struct;
+        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
+                                               &hidl_struct)) {
+            return false;
+        }
+        channelInfo.push_back(hidl_struct);
+    }
+    hidl_ind->channelInfo = channelInfo;
+    std::vector<uint32_t> ndpInstanceIds;
+    for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
+        ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
+    }
+    hidl_ind->ndpInstanceIds = ndpInstanceIds;
+
+    return true;
+}
+
+legacy_hal::wifi_rtt_type convertHidlRttTypeToLegacy(RttType type) {
+    switch (type) {
+        case RttType::ONE_SIDED:
+            return legacy_hal::RTT_TYPE_1_SIDED;
+        case RttType::TWO_SIDED:
+            return legacy_hal::RTT_TYPE_2_SIDED;
+    };
+    CHECK(false);
+}
+
+RttType convertLegacyRttTypeToHidl(legacy_hal::wifi_rtt_type type) {
+    switch (type) {
+        case legacy_hal::RTT_TYPE_1_SIDED:
+            return RttType::ONE_SIDED;
+        case legacy_hal::RTT_TYPE_2_SIDED:
+            return RttType::TWO_SIDED;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::rtt_peer_type convertHidlRttPeerTypeToLegacy(RttPeerType type) {
+    switch (type) {
+        case RttPeerType::AP:
+            return legacy_hal::RTT_PEER_AP;
+        case RttPeerType::STA:
+            return legacy_hal::RTT_PEER_STA;
+        case RttPeerType::P2P_GO:
+            return legacy_hal::RTT_PEER_P2P_GO;
+        case RttPeerType::P2P_CLIENT:
+            return legacy_hal::RTT_PEER_P2P_CLIENT;
+        case RttPeerType::NAN:
+            return legacy_hal::RTT_PEER_NAN;
+    };
+    CHECK(false);
+}
+
+legacy_hal::wifi_channel_width convertHidlWifiChannelWidthToLegacy(
+    WifiChannelWidthInMhz type) {
+    switch (type) {
+        case WifiChannelWidthInMhz::WIDTH_20:
+            return legacy_hal::WIFI_CHAN_WIDTH_20;
+        case WifiChannelWidthInMhz::WIDTH_40:
+            return legacy_hal::WIFI_CHAN_WIDTH_40;
+        case WifiChannelWidthInMhz::WIDTH_80:
+            return legacy_hal::WIFI_CHAN_WIDTH_80;
+        case WifiChannelWidthInMhz::WIDTH_160:
+            return legacy_hal::WIFI_CHAN_WIDTH_160;
+        case WifiChannelWidthInMhz::WIDTH_80P80:
+            return legacy_hal::WIFI_CHAN_WIDTH_80P80;
+        case WifiChannelWidthInMhz::WIDTH_5:
+            return legacy_hal::WIFI_CHAN_WIDTH_5;
+        case WifiChannelWidthInMhz::WIDTH_10:
+            return legacy_hal::WIFI_CHAN_WIDTH_10;
+        case WifiChannelWidthInMhz::WIDTH_INVALID:
+            return legacy_hal::WIFI_CHAN_WIDTH_INVALID;
+    };
+    CHECK(false);
+}
+
+WifiChannelWidthInMhz convertLegacyWifiChannelWidthToHidl(
+    legacy_hal::wifi_channel_width type) {
+    switch (type) {
+        case legacy_hal::WIFI_CHAN_WIDTH_20:
+            return WifiChannelWidthInMhz::WIDTH_20;
+        case legacy_hal::WIFI_CHAN_WIDTH_40:
+            return WifiChannelWidthInMhz::WIDTH_40;
+        case legacy_hal::WIFI_CHAN_WIDTH_80:
+            return WifiChannelWidthInMhz::WIDTH_80;
+        case legacy_hal::WIFI_CHAN_WIDTH_160:
+            return WifiChannelWidthInMhz::WIDTH_160;
+        case legacy_hal::WIFI_CHAN_WIDTH_80P80:
+            return WifiChannelWidthInMhz::WIDTH_80P80;
+        case legacy_hal::WIFI_CHAN_WIDTH_5:
+            return WifiChannelWidthInMhz::WIDTH_5;
+        case legacy_hal::WIFI_CHAN_WIDTH_10:
+            return WifiChannelWidthInMhz::WIDTH_10;
+        case legacy_hal::WIFI_CHAN_WIDTH_INVALID:
+            return WifiChannelWidthInMhz::WIDTH_INVALID;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_preamble convertHidlRttPreambleToLegacy(RttPreamble type) {
+    switch (type) {
+        case RttPreamble::LEGACY:
+            return legacy_hal::WIFI_RTT_PREAMBLE_LEGACY;
+        case RttPreamble::HT:
+            return legacy_hal::WIFI_RTT_PREAMBLE_HT;
+        case RttPreamble::VHT:
+            return legacy_hal::WIFI_RTT_PREAMBLE_VHT;
+    };
+    CHECK(false);
+}
+
+RttPreamble convertLegacyRttPreambleToHidl(legacy_hal::wifi_rtt_preamble type) {
+    switch (type) {
+        case legacy_hal::WIFI_RTT_PREAMBLE_LEGACY:
+            return RttPreamble::LEGACY;
+        case legacy_hal::WIFI_RTT_PREAMBLE_HT:
+            return RttPreamble::HT;
+        case legacy_hal::WIFI_RTT_PREAMBLE_VHT:
+            return RttPreamble::VHT;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_rtt_bw convertHidlRttBwToLegacy(RttBw type) {
+    switch (type) {
+        case RttBw::BW_5MHZ:
+            return legacy_hal::WIFI_RTT_BW_5;
+        case RttBw::BW_10MHZ:
+            return legacy_hal::WIFI_RTT_BW_10;
+        case RttBw::BW_20MHZ:
+            return legacy_hal::WIFI_RTT_BW_20;
+        case RttBw::BW_40MHZ:
+            return legacy_hal::WIFI_RTT_BW_40;
+        case RttBw::BW_80MHZ:
+            return legacy_hal::WIFI_RTT_BW_80;
+        case RttBw::BW_160MHZ:
+            return legacy_hal::WIFI_RTT_BW_160;
+    };
+    CHECK(false);
+}
+
+RttBw convertLegacyRttBwToHidl(legacy_hal::wifi_rtt_bw type) {
+    switch (type) {
+        case legacy_hal::WIFI_RTT_BW_5:
+            return RttBw::BW_5MHZ;
+        case legacy_hal::WIFI_RTT_BW_10:
+            return RttBw::BW_10MHZ;
+        case legacy_hal::WIFI_RTT_BW_20:
+            return RttBw::BW_20MHZ;
+        case legacy_hal::WIFI_RTT_BW_40:
+            return RttBw::BW_40MHZ;
+        case legacy_hal::WIFI_RTT_BW_80:
+            return RttBw::BW_80MHZ;
+        case legacy_hal::WIFI_RTT_BW_160:
+            return RttBw::BW_160MHZ;
+    };
+    CHECK(false) << "Unknown legacy type: " << type;
+}
+
+legacy_hal::wifi_motion_pattern convertHidlRttMotionPatternToLegacy(
+    RttMotionPattern type) {
+    switch (type) {
+        case RttMotionPattern::NOT_EXPECTED:
+            return legacy_hal::WIFI_MOTION_NOT_EXPECTED;
+        case RttMotionPattern::EXPECTED:
+            return legacy_hal::WIFI_MOTION_EXPECTED;
+        case RttMotionPattern::UNKNOWN:
+            return legacy_hal::WIFI_MOTION_UNKNOWN;
+    };
+    CHECK(false);
+}
+
+WifiRatePreamble convertLegacyWifiRatePreambleToHidl(uint8_t preamble) {
+    switch (preamble) {
+        case 0:
+            return WifiRatePreamble::OFDM;
+        case 1:
+            return WifiRatePreamble::CCK;
+        case 2:
+            return WifiRatePreamble::HT;
+        case 3:
+            return WifiRatePreamble::VHT;
+        default:
+            return WifiRatePreamble::RESERVED;
+    };
+    CHECK(false) << "Unknown legacy preamble: " << preamble;
+}
+
+WifiRateNss convertLegacyWifiRateNssToHidl(uint8_t nss) {
+    switch (nss) {
+        case 0:
+            return WifiRateNss::NSS_1x1;
+        case 1:
+            return WifiRateNss::NSS_2x2;
+        case 2:
+            return WifiRateNss::NSS_3x3;
+        case 3:
+            return WifiRateNss::NSS_4x4;
+    };
+    CHECK(false) << "Unknown legacy nss: " << nss;
+    return {};
+}
+
+RttStatus convertLegacyRttStatusToHidl(legacy_hal::wifi_rtt_status status) {
+    switch (status) {
+        case legacy_hal::RTT_STATUS_SUCCESS:
+            return RttStatus::SUCCESS;
+        case legacy_hal::RTT_STATUS_FAILURE:
+            return RttStatus::FAILURE;
+        case legacy_hal::RTT_STATUS_FAIL_NO_RSP:
+            return RttStatus::FAIL_NO_RSP;
+        case legacy_hal::RTT_STATUS_FAIL_REJECTED:
+            return RttStatus::FAIL_REJECTED;
+        case legacy_hal::RTT_STATUS_FAIL_NOT_SCHEDULED_YET:
+            return RttStatus::FAIL_NOT_SCHEDULED_YET;
+        case legacy_hal::RTT_STATUS_FAIL_TM_TIMEOUT:
+            return RttStatus::FAIL_TM_TIMEOUT;
+        case legacy_hal::RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL:
+            return RttStatus::FAIL_AP_ON_DIFF_CHANNEL;
+        case legacy_hal::RTT_STATUS_FAIL_NO_CAPABILITY:
+            return RttStatus::FAIL_NO_CAPABILITY;
+        case legacy_hal::RTT_STATUS_ABORTED:
+            return RttStatus::ABORTED;
+        case legacy_hal::RTT_STATUS_FAIL_INVALID_TS:
+            return RttStatus::FAIL_INVALID_TS;
+        case legacy_hal::RTT_STATUS_FAIL_PROTOCOL:
+            return RttStatus::FAIL_PROTOCOL;
+        case legacy_hal::RTT_STATUS_FAIL_SCHEDULE:
+            return RttStatus::FAIL_SCHEDULE;
+        case legacy_hal::RTT_STATUS_FAIL_BUSY_TRY_LATER:
+            return RttStatus::FAIL_BUSY_TRY_LATER;
+        case legacy_hal::RTT_STATUS_INVALID_REQ:
+            return RttStatus::INVALID_REQ;
+        case legacy_hal::RTT_STATUS_NO_WIFI:
+            return RttStatus::NO_WIFI;
+        case legacy_hal::RTT_STATUS_FAIL_FTM_PARAM_OVERRIDE:
+            return RttStatus::FAIL_FTM_PARAM_OVERRIDE;
+    };
+    CHECK(false) << "Unknown legacy status: " << status;
+}
+
+bool convertHidlWifiChannelInfoToLegacy(
+    const WifiChannelInfo& hidl_info,
+    legacy_hal::wifi_channel_info* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
+    legacy_info->center_freq = hidl_info.centerFreq;
+    legacy_info->center_freq0 = hidl_info.centerFreq0;
+    legacy_info->center_freq1 = hidl_info.centerFreq1;
+    return true;
+}
+
+bool convertLegacyWifiChannelInfoToHidl(
+    const legacy_hal::wifi_channel_info& legacy_info,
+    WifiChannelInfo* hidl_info) {
+    if (!hidl_info) {
+        return false;
+    }
+    *hidl_info = {};
+    hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
+    hidl_info->centerFreq = legacy_info.center_freq;
+    hidl_info->centerFreq0 = legacy_info.center_freq0;
+    hidl_info->centerFreq1 = legacy_info.center_freq1;
+    return true;
+}
+
+bool convertHidlRttConfigToLegacy(const RttConfig& hidl_config,
+                                  legacy_hal::wifi_rtt_config* legacy_config) {
+    if (!legacy_config) {
+        return false;
+    }
+    *legacy_config = {};
+    CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
+    memcpy(legacy_config->addr, hidl_config.addr.data(),
+           hidl_config.addr.size());
+    legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
+    legacy_config->peer = convertHidlRttPeerTypeToLegacy(hidl_config.peer);
+    if (!convertHidlWifiChannelInfoToLegacy(hidl_config.channel,
+                                            &legacy_config->channel)) {
+        return false;
+    }
+    legacy_config->burst_period = hidl_config.burstPeriod;
+    legacy_config->num_burst = hidl_config.numBurst;
+    legacy_config->num_frames_per_burst = hidl_config.numFramesPerBurst;
+    legacy_config->num_retries_per_rtt_frame =
+        hidl_config.numRetriesPerRttFrame;
+    legacy_config->num_retries_per_ftmr = hidl_config.numRetriesPerFtmr;
+    legacy_config->LCI_request = hidl_config.mustRequestLci;
+    legacy_config->LCR_request = hidl_config.mustRequestLcr;
+    legacy_config->burst_duration = hidl_config.burstDuration;
+    legacy_config->preamble =
+        convertHidlRttPreambleToLegacy(hidl_config.preamble);
+    legacy_config->bw = convertHidlRttBwToLegacy(hidl_config.bw);
+    return true;
+}
+
+bool convertHidlVectorOfRttConfigToLegacy(
+    const std::vector<RttConfig>& hidl_configs,
+    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs) {
+    if (!legacy_configs) {
+        return false;
+    }
+    *legacy_configs = {};
+    for (const auto& hidl_config : hidl_configs) {
+        legacy_hal::wifi_rtt_config legacy_config;
+        if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
+            return false;
+        }
+        legacy_configs->push_back(legacy_config);
+    }
+    return true;
+}
+
+bool convertHidlRttLciInformationToLegacy(
+    const RttLciInformation& hidl_info,
+    legacy_hal::wifi_lci_information* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    legacy_info->latitude = hidl_info.latitude;
+    legacy_info->longitude = hidl_info.longitude;
+    legacy_info->altitude = hidl_info.altitude;
+    legacy_info->latitude_unc = hidl_info.latitudeUnc;
+    legacy_info->longitude_unc = hidl_info.longitudeUnc;
+    legacy_info->altitude_unc = hidl_info.altitudeUnc;
+    legacy_info->motion_pattern =
+        convertHidlRttMotionPatternToLegacy(hidl_info.motionPattern);
+    legacy_info->floor = hidl_info.floor;
+    legacy_info->height_above_floor = hidl_info.heightAboveFloor;
+    legacy_info->height_unc = hidl_info.heightUnc;
+    return true;
+}
+
+bool convertHidlRttLcrInformationToLegacy(
+    const RttLcrInformation& hidl_info,
+    legacy_hal::wifi_lcr_information* legacy_info) {
+    if (!legacy_info) {
+        return false;
+    }
+    *legacy_info = {};
+    CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
+    memcpy(legacy_info->country_code, hidl_info.countryCode.data(),
+           hidl_info.countryCode.size());
+    if (hidl_info.civicInfo.size() > sizeof(legacy_info->civic_info)) {
+        return false;
+    }
+    legacy_info->length = hidl_info.civicInfo.size();
+    memcpy(legacy_info->civic_info, hidl_info.civicInfo.c_str(),
+           hidl_info.civicInfo.size());
+    return true;
+}
+
+bool convertHidlRttResponderToLegacy(
+    const RttResponder& hidl_responder,
+    legacy_hal::wifi_rtt_responder* legacy_responder) {
+    if (!legacy_responder) {
+        return false;
+    }
+    *legacy_responder = {};
+    if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel,
+                                            &legacy_responder->channel)) {
+        return false;
+    }
+    legacy_responder->preamble =
+        convertHidlRttPreambleToLegacy(hidl_responder.preamble);
+    return true;
+}
+
+bool convertLegacyRttResponderToHidl(
+    const legacy_hal::wifi_rtt_responder& legacy_responder,
+    RttResponder* hidl_responder) {
+    if (!hidl_responder) {
+        return false;
+    }
+    *hidl_responder = {};
+    if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel,
+                                            &hidl_responder->channel)) {
+        return false;
+    }
+    hidl_responder->preamble =
+        convertLegacyRttPreambleToHidl(legacy_responder.preamble);
+    return true;
+}
+
+bool convertLegacyRttCapabilitiesToHidl(
+    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+    RttCapabilities* hidl_capabilities) {
+    if (!hidl_capabilities) {
+        return false;
+    }
+    *hidl_capabilities = {};
+    hidl_capabilities->rttOneSidedSupported =
+        legacy_capabilities.rtt_one_sided_supported;
+    hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
+    hidl_capabilities->lciSupported = legacy_capabilities.lci_support;
+    hidl_capabilities->lcrSupported = legacy_capabilities.lcr_support;
+    hidl_capabilities->responderSupported =
+        legacy_capabilities.responder_supported;
+    hidl_capabilities->preambleSupport = 0;
+    for (const auto flag : {legacy_hal::WIFI_RTT_PREAMBLE_LEGACY,
+                            legacy_hal::WIFI_RTT_PREAMBLE_HT,
+                            legacy_hal::WIFI_RTT_PREAMBLE_VHT}) {
+        if (legacy_capabilities.preamble_support & flag) {
+            hidl_capabilities->preambleSupport |=
+                static_cast<std::underlying_type<RttPreamble>::type>(
+                    convertLegacyRttPreambleToHidl(flag));
+        }
+    }
+    hidl_capabilities->bwSupport = 0;
+    for (const auto flag :
+         {legacy_hal::WIFI_RTT_BW_5, legacy_hal::WIFI_RTT_BW_10,
+          legacy_hal::WIFI_RTT_BW_20, legacy_hal::WIFI_RTT_BW_40,
+          legacy_hal::WIFI_RTT_BW_80, legacy_hal::WIFI_RTT_BW_160}) {
+        if (legacy_capabilities.bw_support & flag) {
+            hidl_capabilities->bwSupport |=
+                static_cast<std::underlying_type<RttBw>::type>(
+                    convertLegacyRttBwToHidl(flag));
+        }
+    }
+    hidl_capabilities->mcVersion = legacy_capabilities.mc_version;
+    return true;
+}
+
+bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
+                                     WifiRateInfo* hidl_rate) {
+    if (!hidl_rate) {
+        return false;
+    }
+    *hidl_rate = {};
+    hidl_rate->preamble =
+        convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
+    hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
+    hidl_rate->bw = convertLegacyWifiChannelWidthToHidl(
+        static_cast<legacy_hal::wifi_channel_width>(legacy_rate.bw));
+    hidl_rate->rateMcsIdx = legacy_rate.rateMcsIdx;
+    hidl_rate->bitRateInKbps = legacy_rate.bitrate;
+    return true;
+}
+
+bool convertLegacyRttResultToHidl(
+    const legacy_hal::wifi_rtt_result& legacy_result, RttResult* hidl_result) {
+    if (!hidl_result) {
+        return false;
+    }
+    *hidl_result = {};
+    CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
+    memcpy(hidl_result->addr.data(), legacy_result.addr,
+           sizeof(legacy_result.addr));
+    hidl_result->burstNum = legacy_result.burst_num;
+    hidl_result->measurementNumber = legacy_result.measurement_number;
+    hidl_result->successNumber = legacy_result.success_number;
+    hidl_result->numberPerBurstPeer = legacy_result.number_per_burst_peer;
+    hidl_result->status = convertLegacyRttStatusToHidl(legacy_result.status);
+    hidl_result->retryAfterDuration = legacy_result.retry_after_duration;
+    hidl_result->type = convertLegacyRttTypeToHidl(legacy_result.type);
+    hidl_result->rssi = legacy_result.rssi;
+    hidl_result->rssiSpread = legacy_result.rssi_spread;
+    if (!convertLegacyWifiRateInfoToHidl(legacy_result.tx_rate,
+                                         &hidl_result->txRate)) {
+        return false;
+    }
+    if (!convertLegacyWifiRateInfoToHidl(legacy_result.rx_rate,
+                                         &hidl_result->rxRate)) {
+        return false;
+    }
+    hidl_result->rtt = legacy_result.rtt;
+    hidl_result->rttSd = legacy_result.rtt_sd;
+    hidl_result->rttSpread = legacy_result.rtt_spread;
+    hidl_result->distanceInMm = legacy_result.distance_mm;
+    hidl_result->distanceSdInMm = legacy_result.distance_sd_mm;
+    hidl_result->distanceSpreadInMm = legacy_result.distance_spread_mm;
+    hidl_result->timeStampInUs = legacy_result.ts;
+    hidl_result->burstDurationInMs = legacy_result.burst_duration;
+    hidl_result->negotiatedBurstNum = legacy_result.negotiated_burst_num;
+    if (legacy_result.LCI &&
+        !convertLegacyIeToHidl(*legacy_result.LCI, &hidl_result->lci)) {
+        return false;
+    }
+    if (legacy_result.LCR &&
+        !convertLegacyIeToHidl(*legacy_result.LCR, &hidl_result->lcr)) {
+        return false;
+    }
+    return true;
+}
+
+bool convertLegacyVectorOfRttResultToHidl(
+    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+    std::vector<RttResult>* hidl_results) {
+    if (!hidl_results) {
+        return false;
+    }
+    *hidl_results = {};
+    for (const auto legacy_result : legacy_results) {
+        RttResult hidl_result;
+        if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
+            return false;
+        }
+        hidl_results->push_back(hidl_result);
+    }
+    return true;
+}
+}  // namespace hidl_struct_util
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/hidl_struct_util.h b/wifi/1.2/default/hidl_struct_util.h
new file mode 100644
index 0000000..3c789c0
--- /dev/null
+++ b/wifi/1.2/default/hidl_struct_util.h
@@ -0,0 +1,192 @@
+/*
+ * 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 HIDL_STRUCT_UTIL_H_
+#define HIDL_STRUCT_UTIL_H_
+
+#include <vector>
+
+#include <android/hardware/wifi/1.0/IWifiChip.h>
+#include <android/hardware/wifi/1.0/types.h>
+#include <android/hardware/wifi/1.2/IWifiChip.h>
+#include <android/hardware/wifi/1.2/IWifiChipEventCallback.h>
+#include <android/hardware/wifi/1.2/types.h>
+
+#include "wifi_legacy_hal.h"
+
+/**
+ * This file contains a bunch of functions to convert structs from the legacy
+ * HAL to HIDL and vice versa.
+ * TODO(b/32093047): Add unit tests for these conversion methods in the VTS test
+ * suite.
+ */
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace hidl_struct_util {
+using namespace android::hardware::wifi::V1_0;
+
+// Chip conversion methods.
+bool convertLegacyFeaturesToHidlChipCapabilities(
+    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint32_t* hidl_caps);
+bool convertLegacyDebugRingBufferStatusToHidl(
+    const legacy_hal::wifi_ring_buffer_status& legacy_status,
+    WifiDebugRingBufferStatus* hidl_status);
+bool convertLegacyVectorOfDebugRingBufferStatusToHidl(
+    const std::vector<legacy_hal::wifi_ring_buffer_status>& legacy_status_vec,
+    std::vector<WifiDebugRingBufferStatus>* hidl_status_vec);
+bool convertLegacyWakeReasonStatsToHidl(
+    const legacy_hal::WakeReasonStats& legacy_stats,
+    WifiDebugHostWakeReasonStats* hidl_stats);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
+    V1_1::IWifiChip::TxPowerScenario hidl_scenario);
+legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
+    IWifiChip::TxPowerScenario hidl_scenario);
+bool convertLegacyWifiMacInfosToHidl(
+    const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
+    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+
+// STA iface conversion methods.
+bool convertLegacyFeaturesToHidlStaCapabilities(
+    uint32_t legacy_feature_set, uint32_t legacy_logger_feature_set,
+    uint32_t* hidl_caps);
+bool convertLegacyApfCapabilitiesToHidl(
+    const legacy_hal::PacketFilterCapabilities& legacy_caps,
+    StaApfPacketFilterCapabilities* hidl_caps);
+bool convertLegacyGscanCapabilitiesToHidl(
+    const legacy_hal::wifi_gscan_capabilities& legacy_caps,
+    StaBackgroundScanCapabilities* hidl_caps);
+legacy_hal::wifi_band convertHidlWifiBandToLegacy(WifiBand band);
+bool convertHidlGscanParamsToLegacy(
+    const StaBackgroundScanParameters& hidl_scan_params,
+    legacy_hal::wifi_scan_cmd_params* legacy_scan_params);
+// |has_ie_data| indicates whether or not the wifi_scan_result includes 802.11
+// Information Elements (IEs)
+bool convertLegacyGscanResultToHidl(
+    const legacy_hal::wifi_scan_result& legacy_scan_result, bool has_ie_data,
+    StaScanResult* hidl_scan_result);
+// |cached_results| is assumed to not include IEs.
+bool convertLegacyVectorOfCachedGscanResultsToHidl(
+    const std::vector<legacy_hal::wifi_cached_scan_results>&
+        legacy_cached_scan_results,
+    std::vector<StaScanData>* hidl_scan_datas);
+bool convertLegacyLinkLayerStatsToHidl(
+    const legacy_hal::LinkLayerStats& legacy_stats,
+    StaLinkLayerStats* hidl_stats);
+bool convertLegacyRoamingCapabilitiesToHidl(
+    const legacy_hal::wifi_roaming_capabilities& legacy_caps,
+    StaRoamingCapabilities* hidl_caps);
+bool convertHidlRoamingConfigToLegacy(
+    const StaRoamingConfig& hidl_config,
+    legacy_hal::wifi_roaming_config* legacy_config);
+legacy_hal::fw_roaming_state_t convertHidlRoamingStateToLegacy(
+    StaRoamingState state);
+bool convertLegacyVectorOfDebugTxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_tx_report>& legacy_fates,
+    std::vector<WifiDebugTxPacketFateReport>* hidl_fates);
+bool convertLegacyVectorOfDebugRxPacketFateToHidl(
+    const std::vector<legacy_hal::wifi_rx_report>& legacy_fates,
+    std::vector<WifiDebugRxPacketFateReport>* hidl_fates);
+
+// NAN iface conversion methods.
+void convertToWifiNanStatus(legacy_hal::NanStatusType type, const char* str,
+                            size_t max_len, WifiNanStatus* wifiNanStatus);
+bool convertHidlNanEnableRequestToLegacy(
+    const NanEnableRequest& hidl_request,
+    legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequestToLegacy(
+    const NanConfigRequest& hidl_request,
+    legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanEnableRequest_1_2ToLegacy(
+    const NanEnableRequest& hidl_request1,
+    const NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequest_1_2ToLegacy(
+    const NanConfigRequest& hidl_request1,
+    const NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanPublishRequestToLegacy(
+    const NanPublishRequest& hidl_request,
+    legacy_hal::NanPublishRequest* legacy_request);
+bool convertHidlNanSubscribeRequestToLegacy(
+    const NanSubscribeRequest& hidl_request,
+    legacy_hal::NanSubscribeRequest* legacy_request);
+bool convertHidlNanTransmitFollowupRequestToLegacy(
+    const NanTransmitFollowupRequest& hidl_request,
+    legacy_hal::NanTransmitFollowupRequest* legacy_request);
+bool convertHidlNanDataPathInitiatorRequestToLegacy(
+    const NanInitiateDataPathRequest& hidl_request,
+    legacy_hal::NanDataPathInitiatorRequest* legacy_request);
+bool convertHidlNanDataPathIndicationResponseToLegacy(
+    const NanRespondToDataPathIndicationRequest& hidl_response,
+    legacy_hal::NanDataPathIndicationResponse* legacy_response);
+bool convertLegacyNanResponseHeaderToHidl(
+    const legacy_hal::NanResponseMsg& legacy_response,
+    WifiNanStatus* wifiNanStatus);
+bool convertLegacyNanCapabilitiesResponseToHidl(
+    const legacy_hal::NanCapabilities& legacy_response,
+    NanCapabilities* hidl_response);
+bool convertLegacyNanMatchIndToHidl(const legacy_hal::NanMatchInd& legacy_ind,
+                                    NanMatchInd* hidl_ind);
+bool convertLegacyNanFollowupIndToHidl(
+    const legacy_hal::NanFollowupInd& legacy_ind,
+    NanFollowupReceivedInd* hidl_ind);
+bool convertLegacyNanDataPathRequestIndToHidl(
+    const legacy_hal::NanDataPathRequestInd& legacy_ind,
+    NanDataPathRequestInd* hidl_ind);
+bool convertLegacyNanDataPathConfirmIndToHidl(
+    const legacy_hal::NanDataPathConfirmInd& legacy_ind,
+    NanDataPathConfirmInd* hidl_ind);
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+    const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+    NanDataPathScheduleUpdateInd* hidl_ind);
+
+// RTT controller conversion methods.
+bool convertHidlVectorOfRttConfigToLegacy(
+    const std::vector<RttConfig>& hidl_configs,
+    std::vector<legacy_hal::wifi_rtt_config>* legacy_configs);
+bool convertHidlRttLciInformationToLegacy(
+    const RttLciInformation& hidl_info,
+    legacy_hal::wifi_lci_information* legacy_info);
+bool convertHidlRttLcrInformationToLegacy(
+    const RttLcrInformation& hidl_info,
+    legacy_hal::wifi_lcr_information* legacy_info);
+bool convertHidlRttResponderToLegacy(
+    const RttResponder& hidl_responder,
+    legacy_hal::wifi_rtt_responder* legacy_responder);
+bool convertHidlWifiChannelInfoToLegacy(
+    const WifiChannelInfo& hidl_info,
+    legacy_hal::wifi_channel_info* legacy_info);
+bool convertLegacyRttResponderToHidl(
+    const legacy_hal::wifi_rtt_responder& legacy_responder,
+    RttResponder* hidl_responder);
+bool convertLegacyRttCapabilitiesToHidl(
+    const legacy_hal::wifi_rtt_capabilities& legacy_capabilities,
+    RttCapabilities* hidl_capabilities);
+bool convertLegacyVectorOfRttResultToHidl(
+    const std::vector<const legacy_hal::wifi_rtt_result*>& legacy_results,
+    std::vector<RttResult>* hidl_results);
+}  // namespace hidl_struct_util
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HIDL_STRUCT_UTIL_H_
diff --git a/wifi/1.2/default/hidl_sync_util.cpp b/wifi/1.2/default/hidl_sync_util.cpp
new file mode 100644
index 0000000..ad8448a
--- /dev/null
+++ b/wifi/1.2/default/hidl_sync_util.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+#include "hidl_sync_util.h"
+
+namespace {
+std::recursive_mutex g_mutex;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace hidl_sync_util {
+
+std::unique_lock<std::recursive_mutex> acquireGlobalLock() {
+    return std::unique_lock<std::recursive_mutex>{g_mutex};
+}
+
+}  // namespace hidl_sync_util
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/hidl_sync_util.h b/wifi/1.2/default/hidl_sync_util.h
new file mode 100644
index 0000000..8381862
--- /dev/null
+++ b/wifi/1.2/default/hidl_sync_util.h
@@ -0,0 +1,37 @@
+/*
+ * 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 HIDL_SYNC_UTIL_H_
+#define HIDL_SYNC_UTIL_H_
+
+#include <mutex>
+
+// Utility that provides a global lock to synchronize access between
+// the HIDL thread and the legacy HAL's event loop.
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace hidl_sync_util {
+std::unique_lock<std::recursive_mutex> acquireGlobalLock();
+}  // namespace hidl_sync_util
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+#endif  // HIDL_SYNC_UTIL_H_
diff --git a/wifi/1.2/default/ringbuffer.cpp b/wifi/1.2/default/ringbuffer.cpp
new file mode 100644
index 0000000..c126b36
--- /dev/null
+++ b/wifi/1.2/default/ringbuffer.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "ringbuffer.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+
+Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
+
+void Ringbuffer::append(const std::vector<uint8_t>& input) {
+    if (input.size() == 0) {
+        return;
+    }
+    if (input.size() > maxSize_) {
+        LOG(INFO) << "Oversized message of " << input.size()
+                  << " bytes is dropped";
+        return;
+    }
+    data_.push_back(input);
+    size_ += input.size() * sizeof(input[0]);
+    while (size_ > maxSize_) {
+        size_ -= data_.front().size() * sizeof(data_.front()[0]);
+        data_.pop_front();
+    }
+}
+
+const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
+    return data_;
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/ringbuffer.h b/wifi/1.2/default/ringbuffer.h
new file mode 100644
index 0000000..4808e40
--- /dev/null
+++ b/wifi/1.2/default/ringbuffer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RINGBUFFER_H_
+#define RINGBUFFER_H_
+
+#include <list>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+
+/**
+ * Ringbuffer object used to store debug data.
+ */
+class Ringbuffer {
+   public:
+    explicit Ringbuffer(size_t maxSize);
+
+    // Appends the data buffer and deletes from the front until buffer is
+    // within |maxSize_|.
+    void append(const std::vector<uint8_t>& input);
+    const std::list<std::vector<uint8_t>>& getData() const;
+
+   private:
+    std::list<std::vector<uint8_t>> data_;
+    size_t size_;
+    size_t maxSize_;
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // RINGBUFFER_H_
diff --git a/wifi/1.2/default/service.cpp b/wifi/1.2/default/service.cpp
new file mode 100644
index 0000000..01d22bd
--- /dev/null
+++ b/wifi/1.2/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+#include "wifi.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::wifi::V1_2::implementation::feature_flags::
+    WifiFeatureFlags;
+using android::hardware::wifi::V1_2::implementation::legacy_hal::WifiLegacyHal;
+using android::hardware::wifi::V1_2::implementation::mode_controller::
+    WifiModeController;
+
+int main(int /*argc*/, char** argv) {
+    android::base::InitLogging(
+        argv, android::base::LogdLogger(android::base::SYSTEM));
+    LOG(INFO) << "Wifi Hal is booting up...";
+
+    configureRpcThreadpool(1, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    android::sp<android::hardware::wifi::V1_2::IWifi> service =
+        new android::hardware::wifi::V1_2::implementation::Wifi(
+            std::make_shared<WifiLegacyHal>(),
+            std::make_shared<WifiModeController>(),
+            std::make_shared<WifiFeatureFlags>());
+    CHECK_EQ(service->registerAsService(), android::NO_ERROR)
+        << "Failed to register wifi HAL";
+
+    joinRpcThreadpool();
+
+    LOG(INFO) << "Wifi Hal is terminating...";
+    return 0;
+}
diff --git a/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp
new file mode 100644
index 0000000..1d6e9e4
--- /dev/null
+++ b/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "hidl_struct_util.h"
+
+using testing::Test;
+
+namespace {
+constexpr uint32_t kMacId1 = 1;
+constexpr uint32_t kMacId2 = 2;
+constexpr uint32_t kIfaceChannel1 = 3;
+constexpr uint32_t kIfaceChannel2 = 5;
+constexpr char kIfaceName1[] = "wlan0";
+constexpr char kIfaceName2[] = "wlan1";
+}  // namespace
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+class HidlStructUtilTest : public Test {};
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {
+        .wlan_mac_id = kMacId1,
+        .mac_band =
+            legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
+                                                    .channel = kIfaceChannel1};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
+                                                    .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+
+    std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+        legacy_mac_infos, &hidl_radio_mode_infos));
+
+    ASSERT_EQ(1u, hidl_radio_mode_infos.size());
+    auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
+    EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
+    EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
+    ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
+    auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
+              hidl_iface_info1.channel);
+    auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
+    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
+              hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {
+        .wlan_mac_id = kMacId1, .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
+                                                    .channel = kIfaceChannel1};
+    legacy_hal::WifiMacInfo legacy_mac_info2 = {
+        .wlan_mac_id = kMacId2, .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
+                                                    .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+    legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info2);
+
+    std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
+    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+        legacy_mac_infos, &hidl_radio_mode_infos));
+
+    ASSERT_EQ(2u, hidl_radio_mode_infos.size());
+
+    // Find mac info 1.
+    const auto hidl_radio_mode_info1 = std::find_if(
+        hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+        [&legacy_mac_info1](const IWifiChipEventCallback::RadioModeInfo& x) {
+            return x.radioId == legacy_mac_info1.wlan_mac_id;
+        });
+    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
+    EXPECT_EQ(WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
+    ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
+    auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
+              hidl_iface_info1.channel);
+
+    // Find mac info 2.
+    const auto hidl_radio_mode_info2 = std::find_if(
+        hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+        [&legacy_mac_info2](const IWifiChipEventCallback::RadioModeInfo& x) {
+            return x.radioId == legacy_mac_info2.wlan_mac_id;
+        });
+    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
+    EXPECT_EQ(WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
+    ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
+    auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
+              hidl_iface_info2.channel);
+}
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/tests/main.cpp b/wifi/1.2/default/tests/main.cpp
new file mode 100644
index 0000000..9aac837
--- /dev/null
+++ b/wifi/1.2/default/tests/main.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ::testing::InitGoogleMock(&argc, argv);
+    // Force ourselves to always log to stderr
+    android::base::InitLogging(argv, android::base::StderrLogger);
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp
new file mode 100644
index 0000000..8d0b192
--- /dev/null
+++ b/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+
+#include "mock_wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace feature_flags {
+
+MockWifiFeatureFlags::MockWifiFeatureFlags() {}
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.h b/wifi/1.2/default/tests/mock_wifi_feature_flags.h
new file mode 100644
index 0000000..8cf1d4b
--- /dev/null
+++ b/wifi/1.2/default/tests/mock_wifi_feature_flags.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_FEATURE_FLAGS_H_
+#define MOCK_WIFI_FEATURE_FLAGS_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_feature_flags.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace feature_flags {
+
+class MockWifiFeatureFlags : public WifiFeatureFlags {
+   public:
+    MockWifiFeatureFlags();
+
+    MOCK_METHOD0(isAwareSupported, bool());
+    MOCK_METHOD0(isDualInterfaceSupported, bool());
+};
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp
new file mode 100644
index 0000000..8381dde
--- /dev/null
+++ b/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace legacy_hal {
+
+MockWifiLegacyHal::MockWifiLegacyHal() : WifiLegacyHal() {}
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/tests/mock_wifi_legacy_hal.h b/wifi/1.2/default/tests/mock_wifi_legacy_hal.h
new file mode 100644
index 0000000..8e1696e
--- /dev/null
+++ b/wifi/1.2/default/tests/mock_wifi_legacy_hal.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_LEGACY_HAL_H_
+#define MOCK_WIFI_LEGACY_HAL_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace legacy_hal {
+
+class MockWifiLegacyHal : public WifiLegacyHal {
+   public:
+    MockWifiLegacyHal();
+    MOCK_METHOD0(initialize, wifi_error());
+    MOCK_METHOD0(start, wifi_error());
+    MOCK_METHOD2(stop, wifi_error(std::unique_lock<std::recursive_mutex>*,
+                                  const std::function<void()>&));
+    MOCK_METHOD2(setDfsFlag, wifi_error(const std::string&, bool));
+    MOCK_METHOD2(nanRegisterCallbackHandlers,
+                 wifi_error(const std::string&, const NanCallbackHandlers&));
+    MOCK_METHOD2(nanDisableRequest,
+                 wifi_error(const std::string&, transaction_id));
+    MOCK_METHOD3(nanDataInterfaceDelete,
+                 wifi_error(const std::string&, transaction_id,
+                            const std::string&));
+};
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp
new file mode 100644
index 0000000..461a581
--- /dev/null
+++ b/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "mock_wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace mode_controller {
+
+MockWifiModeController::MockWifiModeController() : WifiModeController() {}
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.h b/wifi/1.2/default/tests/mock_wifi_mode_controller.h
new file mode 100644
index 0000000..50c3e35
--- /dev/null
+++ b/wifi/1.2/default/tests/mock_wifi_mode_controller.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MOCK_WIFI_MODE_CONTROLLER_H_
+#define MOCK_WIFI_MODE_CONTROLLER_H_
+
+#include <gmock/gmock.h>
+
+#include "wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace mode_controller {
+
+class MockWifiModeController : public WifiModeController {
+   public:
+    MockWifiModeController();
+    MOCK_METHOD0(initialize, bool());
+    MOCK_METHOD1(changeFirmwareMode, bool(IfaceType));
+    MOCK_METHOD1(isFirmwareModeChangeNeeded, bool(IfaceType));
+    MOCK_METHOD0(deinitialize, bool());
+};
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // MOCK_WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.2/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.2/default/tests/ringbuffer_unit_tests.cpp
new file mode 100644
index 0000000..ad5289b
--- /dev/null
+++ b/wifi/1.2/default/tests/ringbuffer_unit_tests.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+
+#include "ringbuffer.h"
+
+using testing::Return;
+using testing::Test;
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+
+class RingbufferTest : public Test {
+   public:
+    const uint32_t maxBufferSize_ = 10;
+    Ringbuffer buffer_{maxBufferSize_};
+};
+
+TEST_F(RingbufferTest, CreateEmptyBuffer) {
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, CanUseFullBufferCapacity) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    buffer_.append(input);
+    buffer_.append(input2);
+    ASSERT_EQ(2u, buffer_.getData().size());
+    EXPECT_EQ(input, buffer_.getData().front());
+    EXPECT_EQ(input2, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, OldDataIsRemovedOnOverflow) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    const std::vector<uint8_t> input3 = {'G'};
+    buffer_.append(input);
+    buffer_.append(input2);
+    buffer_.append(input3);
+    ASSERT_EQ(2u, buffer_.getData().size());
+    EXPECT_EQ(input2, buffer_.getData().front());
+    EXPECT_EQ(input3, buffer_.getData().back());
+}
+
+TEST_F(RingbufferTest, MultipleOldDataIsRemovedOnOverflow) {
+    const std::vector<uint8_t> input(maxBufferSize_ / 2, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ / 2, '1');
+    const std::vector<uint8_t> input3(maxBufferSize_, '2');
+    buffer_.append(input);
+    buffer_.append(input2);
+    buffer_.append(input3);
+    ASSERT_EQ(1u, buffer_.getData().size());
+    EXPECT_EQ(input3, buffer_.getData().front());
+}
+
+TEST_F(RingbufferTest, AppendingEmptyBufferDoesNotAddGarbage) {
+    const std::vector<uint8_t> input = {};
+    buffer_.append(input);
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendIsDropped) {
+    const std::vector<uint8_t> input(maxBufferSize_ + 1, '0');
+    buffer_.append(input);
+    ASSERT_TRUE(buffer_.getData().empty());
+}
+
+TEST_F(RingbufferTest, OversizedAppendDoesNotDropExistingData) {
+    const std::vector<uint8_t> input(maxBufferSize_, '0');
+    const std::vector<uint8_t> input2(maxBufferSize_ + 1, '1');
+    buffer_.append(input);
+    buffer_.append(input2);
+    ASSERT_EQ(1u, buffer_.getData().size());
+    EXPECT_EQ(input, buffer_.getData().front());
+}
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/tests/runtests.sh b/wifi/1.2/default/tests/runtests.sh
new file mode 100755
index 0000000..966a6a7
--- /dev/null
+++ b/wifi/1.2/default/tests/runtests.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+
+# Copyright(C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0(the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http:// www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+  echo "You need to source and lunch before you can use this script"
+  exit 1
+fi
+
+echo "Running tests"
+set -e # fail early
+
+#NOTE We can't actually run these commands, since they rely on functions added by
+#build / envsetup.sh to the bash shell environment.
+echo "+ mmma -j32 $ANDROID_BUILD_TOP/"
+make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk \
+    MODULES-IN-hardware-interfaces-wifi-1.2-default
+
+set -x # print commands
+
+adb wait-for-device
+adb root
+adb wait-for-device
+
+#'disable-verity' will appear in 'adb remount' output if
+#dm - verity is enabled and needs to be disabled.
+if adb remount | grep 'disable-verity'; then
+  adb disable-verity
+  adb reboot
+  adb wait-for-device
+  adb root
+  adb wait-for-device
+  adb remount
+fi
+
+adb sync
+
+adb shell /data/nativetest/vendor/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests
diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
new file mode 100644
index 0000000..1b082d0
--- /dev/null
+++ b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN  // This is weird, NAN is defined in bionic/libc/include/math.h:38
+#include "wifi_chip.h"
+
+#include "mock_wifi_feature_flags.h"
+#include "mock_wifi_legacy_hal.h"
+#include "mock_wifi_mode_controller.h"
+
+using testing::NiceMock;
+using testing::Return;
+using testing::Test;
+
+namespace {
+using android::hardware::wifi::V1_0::ChipId;
+
+constexpr ChipId kFakeChipId = 5;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+
+class WifiChipTest : public Test {
+   protected:
+    void setupV1IfaceCombination() {
+        EXPECT_CALL(*feature_flags_, isAwareSupported())
+            .WillRepeatedly(testing::Return(false));
+        EXPECT_CALL(*feature_flags_, isDualInterfaceSupported())
+            .WillRepeatedly(testing::Return(false));
+    }
+
+    void setupV1_AwareIfaceCombination() {
+        EXPECT_CALL(*feature_flags_, isAwareSupported())
+            .WillRepeatedly(testing::Return(true));
+        EXPECT_CALL(*feature_flags_, isDualInterfaceSupported())
+            .WillRepeatedly(testing::Return(false));
+    }
+
+    void setupV2_AwareIfaceCombination() {
+        EXPECT_CALL(*feature_flags_, isAwareSupported())
+            .WillRepeatedly(testing::Return(true));
+        EXPECT_CALL(*feature_flags_, isDualInterfaceSupported())
+            .WillRepeatedly(testing::Return(true));
+    }
+
+    void assertNumberOfModes(uint32_t num_modes) {
+        chip_->getAvailableModes(
+            [num_modes](const WifiStatus& status,
+                        const std::vector<WifiChip::ChipMode>& modes) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                // V2_Aware has 1 mode of operation.
+                ASSERT_EQ(num_modes, modes.size());
+            });
+    }
+
+    void findModeAndConfigureForIfaceType(const IfaceType& type) {
+        // This should be aligned with kInvalidModeId in wifi_chip.cpp.
+        ChipModeId mode_id = UINT32_MAX;
+        chip_->getAvailableModes(
+            [&mode_id, &type](const WifiStatus& status,
+                              const std::vector<WifiChip::ChipMode>& modes) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                for (const auto& mode : modes) {
+                    for (const auto& combination : mode.availableCombinations) {
+                        for (const auto& limit : combination.limits) {
+                            if (limit.types.end() !=
+                                std::find(limit.types.begin(),
+                                          limit.types.end(), type)) {
+                                mode_id = mode.id;
+                            }
+                        }
+                    }
+                }
+            });
+        ASSERT_NE(UINT32_MAX, mode_id);
+
+        chip_->configureChip(mode_id, [](const WifiStatus& status) {
+            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+        });
+    }
+
+    // Returns an empty string on error.
+    std::string createIface(const IfaceType& type) {
+        std::string iface_name;
+        if (type == IfaceType::AP) {
+            chip_->createApIface([&iface_name](const WifiStatus& status,
+                                               const sp<IWifiApIface>& iface) {
+                if (WifiStatusCode::SUCCESS == status.code) {
+                    ASSERT_NE(iface.get(), nullptr);
+                    iface->getName([&iface_name](const WifiStatus& status,
+                                                 const hidl_string& name) {
+                        ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                        iface_name = name.c_str();
+                    });
+                }
+            });
+        } else if (type == IfaceType::NAN) {
+            chip_->createNanIface(
+                [&iface_name](
+                    const WifiStatus& status,
+                    const sp<android::hardware::wifi::V1_0::IWifiNanIface>&
+                        iface) {
+                    if (WifiStatusCode::SUCCESS == status.code) {
+                        ASSERT_NE(iface.get(), nullptr);
+                        iface->getName([&iface_name](const WifiStatus& status,
+                                                     const hidl_string& name) {
+                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                            iface_name = name.c_str();
+                        });
+                    }
+                });
+        } else if (type == IfaceType::P2P) {
+            chip_->createP2pIface(
+                [&iface_name](const WifiStatus& status,
+                              const sp<IWifiP2pIface>& iface) {
+                    if (WifiStatusCode::SUCCESS == status.code) {
+                        ASSERT_NE(iface.get(), nullptr);
+                        iface->getName([&iface_name](const WifiStatus& status,
+                                                     const hidl_string& name) {
+                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                            iface_name = name.c_str();
+                        });
+                    }
+                });
+        } else if (type == IfaceType::STA) {
+            chip_->createStaIface(
+                [&iface_name](const WifiStatus& status,
+                              const sp<IWifiStaIface>& iface) {
+                    if (WifiStatusCode::SUCCESS == status.code) {
+                        ASSERT_NE(iface.get(), nullptr);
+                        iface->getName([&iface_name](const WifiStatus& status,
+                                                     const hidl_string& name) {
+                            ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+                            iface_name = name.c_str();
+                        });
+                    }
+                });
+        }
+        return iface_name;
+    }
+
+    void removeIface(const IfaceType& type, const std::string& iface_name) {
+        if (type == IfaceType::AP) {
+            chip_->removeApIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        } else if (type == IfaceType::NAN) {
+            chip_->removeNanIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        } else if (type == IfaceType::P2P) {
+            chip_->removeP2pIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        } else if (type == IfaceType::STA) {
+            chip_->removeStaIface(iface_name, [](const WifiStatus& status) {
+                ASSERT_EQ(WifiStatusCode::SUCCESS, status.code);
+            });
+        }
+    }
+
+   public:
+    void SetUp() override {
+        chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_,
+                             feature_flags_);
+
+        EXPECT_CALL(*mode_controller_, changeFirmwareMode(testing::_))
+            .WillRepeatedly(testing::Return(true));
+        EXPECT_CALL(*legacy_hal_, start())
+            .WillRepeatedly(testing::Return(legacy_hal::WIFI_SUCCESS));
+    }
+
+   private:
+    sp<WifiChip> chip_;
+    ChipId chip_id_ = kFakeChipId;
+    std::shared_ptr<NiceMock<legacy_hal::MockWifiLegacyHal>> legacy_hal_{
+        new NiceMock<legacy_hal::MockWifiLegacyHal>};
+    std::shared_ptr<NiceMock<mode_controller::MockWifiModeController>>
+        mode_controller_{new NiceMock<mode_controller::MockWifiModeController>};
+    std::shared_ptr<NiceMock<feature_flags::MockWifiFeatureFlags>>
+        feature_flags_{new NiceMock<feature_flags::MockWifiFeatureFlags>};
+};
+
+////////// V1 Iface Combinations ////////////
+// Mode 1 - STA + P2P
+// Mode 2 - AP
+class WifiChipV1IfaceCombinationTest : public WifiChipTest {
+   public:
+    void SetUp() override {
+        setupV1IfaceCombination();
+        WifiChipTest::SetUp();
+        // V1 has 2 modes of operation.
+        assertNumberOfModes(2u);
+    }
+};
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, StaMode_CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+////////// V1 + Aware Iface Combinations ////////////
+// Mode 1 - STA + P2P/NAN
+// Mode 2 - AP
+class WifiChipV1_AwareIfaceCombinationTest : public WifiChipTest {
+   public:
+    void SetUp() override {
+        setupV1_AwareIfaceCombination();
+        WifiChipTest::SetUp();
+        // V1_Aware has 2 modes of operation.
+        assertNumberOfModes(2u);
+    }
+};
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, StaMode_CreateAp_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+       StaMode_CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+       StaMode_CreateStaNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+       StaMode_CreateStaP2PNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+       StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest,
+       StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto nan_iface_name = createIface(IfaceType::NAN);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateSta_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV1_AwareIfaceCombinationTest, ApMode_CreateNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+////////// V2 + Aware Iface Combinations ////////////
+// Mode 1 - STA + STA/AP
+//        - STA + P2P/NAN
+class WifiChipV2_AwareIfaceCombinationTest : public WifiChipTest {
+   public:
+    void SetUp() override {
+        setupV2_AwareIfaceCombination();
+        WifiChipTest::SetUp();
+        // V2_Aware has 1 mode of operation.
+        assertNumberOfModes(1u);
+    }
+};
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaSta_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaAp_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaStaAp_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       CreateStaAp_AfterStaRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto sta_iface_name = createIface(IfaceType::STA);
+    ASSERT_FALSE(sta_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
+
+    // After removing STA iface, AP iface creation should succeed.
+    removeIface(IfaceType::STA, sta_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       CreateStaSta_AfterApRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(ap_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::STA).empty());
+
+    // After removing AP  iface, STA iface creation should succeed.
+    removeIface(IfaceType::AP, ap_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2p_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaNan_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateStaP2PNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto nan_iface_name = createIface(IfaceType::NAN);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApNan_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, CreateApP2p_ShouldFail) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       StaMode_CreateStaNan_AfterP2pRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto p2p_iface_name = createIface(IfaceType::P2P);
+    ASSERT_FALSE(p2p_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::NAN).empty());
+
+    // After removing P2P iface, NAN iface creation should succeed.
+    removeIface(IfaceType::P2P, p2p_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::NAN).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       StaMode_CreateStaP2p_AfterNanRemove_ShouldSucceed) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    const auto nan_iface_name = createIface(IfaceType::NAN);
+    ASSERT_FALSE(nan_iface_name.empty());
+    ASSERT_TRUE(createIface(IfaceType::P2P).empty());
+
+    // After removing NAN iface, P2P iface creation should succeed.
+    removeIface(IfaceType::NAN, nan_iface_name);
+    ASSERT_FALSE(createIface(IfaceType::P2P).empty());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       CreateStaSta_EnsureDifferentIfaceNames) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    const auto sta1_iface_name = createIface(IfaceType::STA);
+    const auto sta2_iface_name = createIface(IfaceType::STA);
+    ASSERT_FALSE(sta1_iface_name.empty());
+    ASSERT_FALSE(sta2_iface_name.empty());
+    ASSERT_NE(sta1_iface_name, sta2_iface_name);
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest,
+       CreateStaAp_EnsureDifferentIfaceNames) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    const auto sta_iface_name = createIface(IfaceType::STA);
+    const auto ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(sta_iface_name.empty());
+    ASSERT_FALSE(ap_iface_name.empty());
+    ASSERT_NE(sta_iface_name, ap_iface_name);
+}
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi.cpp b/wifi/1.2/default/wifi.cpp
new file mode 100644
index 0000000..79f921f
--- /dev/null
+++ b/wifi/1.2/default/wifi.cpp
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "wifi.h"
+#include "wifi_status_util.h"
+
+namespace {
+// Chip ID to use for the only supported chip.
+static constexpr android::hardware::wifi::V1_0::ChipId kChipId = 0;
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
+
+Wifi::Wifi(
+    const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::shared_ptr<mode_controller::WifiModeController> mode_controller,
+    const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+    : legacy_hal_(legacy_hal),
+      mode_controller_(mode_controller),
+      feature_flags_(feature_flags),
+      run_state_(RunState::STOPPED) {}
+
+bool Wifi::isValid() {
+    // This object is always valid.
+    return true;
+}
+
+Return<void> Wifi::registerEventCallback(
+    const sp<IWifiEventCallback>& event_callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::registerEventCallbackInternal, hidl_status_cb,
+                           event_callback);
+}
+
+Return<bool> Wifi::isStarted() { return run_state_ != RunState::STOPPED; }
+
+Return<void> Wifi::start(start_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::startInternal, hidl_status_cb);
+}
+
+Return<void> Wifi::stop(stop_cb hidl_status_cb) {
+    return validateAndCallWithLock(this, WifiStatusCode::ERROR_UNKNOWN,
+                                   &Wifi::stopInternal, hidl_status_cb);
+}
+
+Return<void> Wifi::getChipIds(getChipIds_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::getChipIdsInternal, hidl_status_cb);
+}
+
+Return<void> Wifi::getChip(ChipId chip_id, getChip_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN,
+                           &Wifi::getChipInternal, hidl_status_cb, chip_id);
+}
+
+Return<void> Wifi::debug(const hidl_handle& handle,
+                         const hidl_vec<hidl_string>&) {
+    LOG(INFO) << "-----------Debug is called----------------";
+    if (!chip_.get()) {
+        return Void();
+    }
+    return chip_->debug(handle, {});
+}
+
+WifiStatus Wifi::registerEventCallbackInternal(
+    const sp<IWifiEventCallback>& event_callback) {
+    if (!event_cb_handler_.addCallback(event_callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::startInternal() {
+    if (run_state_ == RunState::STARTED) {
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    } else if (run_state_ == RunState::STOPPING) {
+        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
+                                "HAL is stopping");
+    }
+    WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
+    if (wifi_status.code == WifiStatusCode::SUCCESS) {
+        // Create the chip instance once the HAL is started.
+        chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
+                             feature_flags_);
+        run_state_ = RunState::STARTED;
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onStart().isOk()) {
+                LOG(ERROR) << "Failed to invoke onStart callback";
+            };
+        }
+        LOG(INFO) << "Wifi HAL started";
+    } else {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onFailure(wifi_status).isOk()) {
+                LOG(ERROR) << "Failed to invoke onFailure callback";
+            }
+        }
+        LOG(ERROR) << "Wifi HAL start failed";
+    }
+    return wifi_status;
+}
+
+WifiStatus Wifi::stopInternal(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+    if (run_state_ == RunState::STOPPED) {
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    } else if (run_state_ == RunState::STOPPING) {
+        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
+                                "HAL is stopping");
+    }
+    // Clear the chip object and its child objects since the HAL is now
+    // stopped.
+    if (chip_.get()) {
+        chip_->invalidate();
+        chip_.clear();
+    }
+    WifiStatus wifi_status = stopLegacyHalAndDeinitializeModeController(lock);
+    if (wifi_status.code == WifiStatusCode::SUCCESS) {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onStop().isOk()) {
+                LOG(ERROR) << "Failed to invoke onStop callback";
+            };
+        }
+        LOG(INFO) << "Wifi HAL stopped";
+    } else {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onFailure(wifi_status).isOk()) {
+                LOG(ERROR) << "Failed to invoke onFailure callback";
+            }
+        }
+        LOG(ERROR) << "Wifi HAL stop failed";
+    }
+    return wifi_status;
+}
+
+std::pair<WifiStatus, std::vector<ChipId>> Wifi::getChipIdsInternal() {
+    std::vector<ChipId> chip_ids;
+    if (chip_.get()) {
+        chip_ids.emplace_back(kChipId);
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), std::move(chip_ids)};
+}
+
+std::pair<WifiStatus, sp<IWifiChip>> Wifi::getChipInternal(ChipId chip_id) {
+    if (!chip_.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_STARTED), nullptr};
+    }
+    if (chip_id != kChipId) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_};
+}
+
+WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
+    if (!mode_controller_->initialize()) {
+        LOG(ERROR) << "Failed to initialize firmware mode controller";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to initialize legacy HAL: "
+                   << legacyErrorToString(legacy_status);
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus Wifi::stopLegacyHalAndDeinitializeModeController(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock) {
+    run_state_ = RunState::STOPPING;
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_->stop(lock, [&]() { run_state_ = RunState::STOPPED; });
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to stop legacy HAL: "
+                   << legacyErrorToString(legacy_status);
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    if (!mode_controller_->deinitialize()) {
+        LOG(ERROR) << "Failed to deinitialize firmware mode controller";
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi.h b/wifi/1.2/default/wifi.h
new file mode 100644
index 0000000..86919b1
--- /dev/null
+++ b/wifi/1.2/default/wifi.h
@@ -0,0 +1,96 @@
+/*
+ * 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 WIFI_H_
+#define WIFI_H_
+
+#include <functional>
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.2/IWifi.h>
+#include <utils/Looper.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_chip.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+
+/**
+ * Root HIDL interface object used to control the Wifi HAL.
+ */
+class Wifi : public V1_2::IWifi {
+   public:
+    Wifi(const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+         const std::shared_ptr<mode_controller::WifiModeController>
+             mode_controller,
+         const std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+
+    bool isValid();
+
+    // HIDL methods exposed.
+    Return<void> registerEventCallback(
+        const sp<IWifiEventCallback>& event_callback,
+        registerEventCallback_cb hidl_status_cb) override;
+    Return<bool> isStarted() override;
+    Return<void> start(start_cb hidl_status_cb) override;
+    Return<void> stop(stop_cb hidl_status_cb) override;
+    Return<void> getChipIds(getChipIds_cb hidl_status_cb) override;
+    Return<void> getChip(ChipId chip_id, getChip_cb hidl_status_cb) override;
+    Return<void> debug(const hidl_handle& handle,
+                       const hidl_vec<hidl_string>& options) override;
+
+   private:
+    enum class RunState { STOPPED, STARTED, STOPPING };
+
+    // Corresponding worker functions for the HIDL methods.
+    WifiStatus registerEventCallbackInternal(
+        const sp<IWifiEventCallback>& event_callback);
+    WifiStatus startInternal();
+    WifiStatus stopInternal(std::unique_lock<std::recursive_mutex>* lock);
+    std::pair<WifiStatus, std::vector<ChipId>> getChipIdsInternal();
+    std::pair<WifiStatus, sp<IWifiChip>> getChipInternal(ChipId chip_id);
+
+    WifiStatus initializeModeControllerAndLegacyHal();
+    WifiStatus stopLegacyHalAndDeinitializeModeController(
+        std::unique_lock<std::recursive_mutex>* lock);
+
+    // Instance is created in this root level |IWifi| HIDL interface object
+    // and shared with all the child HIDL interface objects.
+    std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::shared_ptr<mode_controller::WifiModeController> mode_controller_;
+    std::shared_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
+    RunState run_state_;
+    sp<WifiChip> chip_;
+    hidl_callback_util::HidlCallbackHandler<IWifiEventCallback>
+        event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(Wifi);
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_H_
diff --git a/wifi/1.2/default/wifi_ap_iface.cpp b/wifi/1.2/default/wifi_ap_iface.cpp
new file mode 100644
index 0000000..92b7b48
--- /dev/null
+++ b/wifi/1.2/default/wifi_ap_iface.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_ap_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiApIface::WifiApIface(
+    const std::string& ifname,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
+
+void WifiApIface::invalidate() {
+    legacy_hal_.reset();
+    is_valid_ = false;
+}
+
+bool WifiApIface::isValid() { return is_valid_; }
+
+std::string WifiApIface::getName() { return ifname_; }
+
+Return<void> WifiApIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiApIface::setCountryCode(const hidl_array<int8_t, 2>& code,
+                                         setCountryCode_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::setCountryCodeInternal, hidl_status_cb,
+                           code);
+}
+
+Return<void> WifiApIface::getValidFrequenciesForBand(
+    WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getValidFrequenciesForBandInternal,
+                           hidl_status_cb, band);
+}
+
+std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiApIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::AP};
+}
+
+WifiStatus WifiApIface::setCountryCodeInternal(
+    const std::array<int8_t, 2>& code) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setCountryCode(ifname_, code);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+WifiApIface::getValidFrequenciesForBandInternal(WifiBand band) {
+    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
+                  "Size mismatch");
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint32_t> valid_frequencies;
+    std::tie(legacy_status, valid_frequencies) =
+        legacy_hal_.lock()->getValidFrequenciesForBand(
+            ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
+    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
+}
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_ap_iface.h b/wifi/1.2/default/wifi_ap_iface.h
new file mode 100644
index 0000000..5363ec2
--- /dev/null
+++ b/wifi/1.2/default/wifi_ap_iface.h
@@ -0,0 +1,73 @@
+/*
+ * 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 WIFI_AP_IFACE_H_
+#define WIFI_AP_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiApIface.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a AP Iface instance.
+ */
+class WifiApIface : public V1_0::IWifiApIface {
+   public:
+    WifiApIface(const std::string& ifname,
+                const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+    Return<void> setCountryCode(const hidl_array<int8_t, 2>& code,
+                                setCountryCode_cb hidl_status_cb) override;
+    Return<void> getValidFrequenciesForBand(
+        WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override;
+
+   private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+    WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
+    std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+    getValidFrequenciesForBandInternal(WifiBand band);
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiApIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_AP_IFACE_H_
diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp
new file mode 100644
index 0000000..201b8e4
--- /dev/null
+++ b/wifi/1.2/default/wifi_chip.cpp
@@ -0,0 +1,1393 @@
+/*
+ * 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.
+ */
+
+#include <fcntl.h>
+
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <cutils/properties.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_chip.h"
+#include "wifi_status_util.h"
+
+namespace {
+using android::base::unique_fd;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::wifi::V1_0::ChipModeId;
+using android::hardware::wifi::V1_0::IfaceType;
+using android::hardware::wifi::V1_0::IWifiChip;
+using android::sp;
+
+constexpr ChipModeId kInvalidModeId = UINT32_MAX;
+// These mode ID's should be unique (even across combo versions). Refer to
+// handleChipConfiguration() for it's usage.
+// Mode ID's for V1
+constexpr ChipModeId kV1StaChipModeId = 0;
+constexpr ChipModeId kV1ApChipModeId = 1;
+// Mode ID for V2
+constexpr ChipModeId kV2ChipModeId = 2;
+
+constexpr char kCpioMagic[] = "070701";
+constexpr size_t kMaxBufferSizeBytes = 1024 * 1024;
+constexpr uint32_t kMaxRingBufferFileAgeSeconds = 60 * 60;
+constexpr char kTombstoneFolderPath[] = "/data/vendor/tombstones/wifi/";
+
+template <typename Iface>
+void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
+    iface->invalidate();
+    ifaces.erase(std::remove(ifaces.begin(), ifaces.end(), iface),
+                 ifaces.end());
+}
+
+template <typename Iface>
+void invalidateAndClearAll(std::vector<sp<Iface>>& ifaces) {
+    for (const auto& iface : ifaces) {
+        iface->invalidate();
+    }
+    ifaces.clear();
+}
+
+template <typename Iface>
+std::vector<hidl_string> getNames(std::vector<sp<Iface>>& ifaces) {
+    std::vector<hidl_string> names;
+    for (const auto& iface : ifaces) {
+        names.emplace_back(iface->getName());
+    }
+    return names;
+}
+
+template <typename Iface>
+sp<Iface> findUsingName(std::vector<sp<Iface>>& ifaces,
+                        const std::string& name) {
+    std::vector<hidl_string> names;
+    for (const auto& iface : ifaces) {
+        if (name == iface->getName()) {
+            return iface;
+        }
+    }
+    return nullptr;
+}
+
+std::string getWlan0IfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    property_get("wifi.interface", buffer.data(), "wlan0");
+    return buffer.data();
+}
+
+std::string getWlan1IfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    property_get("wifi.concurrent.interface", buffer.data(), "wlan1");
+    return buffer.data();
+}
+
+std::string getP2pIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> buffer;
+    property_get("wifi.direct.interface", buffer.data(), "p2p0");
+    return buffer.data();
+}
+
+// delete files older than a predefined time in the wifi tombstone dir
+bool removeOldFilesInternal() {
+    time_t now = time(0);
+    const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
+    DIR* dir_dump = opendir(kTombstoneFolderPath);
+    if (!dir_dump) {
+        LOG(ERROR) << "Failed to open directory: " << strerror(errno);
+        return false;
+    }
+    unique_fd dir_auto_closer(dirfd(dir_dump));
+    struct dirent* dp;
+    bool success = true;
+    while ((dp = readdir(dir_dump))) {
+        if (dp->d_type != DT_REG) {
+            continue;
+        }
+        std::string cur_file_name(dp->d_name);
+        struct stat cur_file_stat;
+        std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+        if (stat(cur_file_path.c_str(), &cur_file_stat) == -1) {
+            LOG(ERROR) << "Failed to get file stat for " << cur_file_path
+                       << ": " << strerror(errno);
+            success = false;
+            continue;
+        }
+        if (cur_file_stat.st_mtime >= delete_files_before) {
+            continue;
+        }
+        if (unlink(cur_file_path.c_str()) != 0) {
+            LOG(ERROR) << "Error deleting file " << strerror(errno);
+            success = false;
+        }
+    }
+    return success;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteHeader(int out_fd, struct stat& st, const char* file_name,
+                     size_t file_name_len) {
+    std::array<char, 32 * 1024> read_buf;
+    ssize_t llen =
+        sprintf(read_buf.data(),
+                "%s%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
+                kCpioMagic, static_cast<int>(st.st_ino), st.st_mode, st.st_uid,
+                st.st_gid, static_cast<int>(st.st_nlink),
+                static_cast<int>(st.st_mtime), static_cast<int>(st.st_size),
+                major(st.st_dev), minor(st.st_dev), major(st.st_rdev),
+                minor(st.st_rdev), static_cast<uint32_t>(file_name_len), 0);
+    if (write(out_fd, read_buf.data(), llen) == -1) {
+        LOG(ERROR) << "Error writing cpio header to file " << file_name << " "
+                   << strerror(errno);
+        return false;
+    }
+    if (write(out_fd, file_name, file_name_len) == -1) {
+        LOG(ERROR) << "Error writing filename to file " << file_name << " "
+                   << strerror(errno);
+        return false;
+    }
+
+    // NUL Pad header up to 4 multiple bytes.
+    llen = (llen + file_name_len) % 4;
+    if (llen != 0) {
+        const uint32_t zero = 0;
+        if (write(out_fd, &zero, 4 - llen) == -1) {
+            LOG(ERROR) << "Error padding 0s to file " << file_name << " "
+                       << strerror(errno);
+            return false;
+        }
+    }
+    return true;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+size_t cpioWriteFileContent(int fd_read, int out_fd, struct stat& st) {
+    // writing content of file
+    std::array<char, 32 * 1024> read_buf;
+    ssize_t llen = st.st_size;
+    size_t n_error = 0;
+    while (llen > 0) {
+        ssize_t bytes_read = read(fd_read, read_buf.data(), read_buf.size());
+        if (bytes_read == -1) {
+            LOG(ERROR) << "Error reading file " << strerror(errno);
+            return ++n_error;
+        }
+        llen -= bytes_read;
+        if (write(out_fd, read_buf.data(), bytes_read) == -1) {
+            LOG(ERROR) << "Error writing data to file " << strerror(errno);
+            return ++n_error;
+        }
+        if (bytes_read == 0) {  // this should never happen, but just in case
+                                // to unstuck from while loop
+            LOG(ERROR) << "Unexpected read result for " << strerror(errno);
+            n_error++;
+            break;
+        }
+    }
+    llen = st.st_size % 4;
+    if (llen != 0) {
+        const uint32_t zero = 0;
+        if (write(out_fd, &zero, 4 - llen) == -1) {
+            LOG(ERROR) << "Error padding 0s to file " << strerror(errno);
+            return ++n_error;
+        }
+    }
+    return n_error;
+}
+
+// Helper function for |cpioArchiveFilesInDir|
+bool cpioWriteFileTrailer(int out_fd) {
+    std::array<char, 4096> read_buf;
+    read_buf.fill(0);
+    if (write(out_fd, read_buf.data(),
+              sprintf(read_buf.data(), "070701%040X%056X%08XTRAILER!!!", 1,
+                      0x0b, 0) +
+                  4) == -1) {
+        LOG(ERROR) << "Error writing trailing bytes " << strerror(errno);
+        return false;
+    }
+    return true;
+}
+
+// Archives all files in |input_dir| and writes result into |out_fd|
+// Logic obtained from //external/toybox/toys/posix/cpio.c "Output cpio archive"
+// portion
+size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
+    struct dirent* dp;
+    size_t n_error = 0;
+    DIR* dir_dump = opendir(input_dir);
+    if (!dir_dump) {
+        LOG(ERROR) << "Failed to open directory: " << strerror(errno);
+        return ++n_error;
+    }
+    unique_fd dir_auto_closer(dirfd(dir_dump));
+    while ((dp = readdir(dir_dump))) {
+        if (dp->d_type != DT_REG) {
+            continue;
+        }
+        std::string cur_file_name(dp->d_name);
+        // string.size() does not include the null terminator. The cpio FreeBSD
+        // file header expects the null character to be included in the length.
+        const size_t file_name_len = cur_file_name.size() + 1;
+        struct stat st;
+        const std::string cur_file_path = kTombstoneFolderPath + cur_file_name;
+        if (stat(cur_file_path.c_str(), &st) == -1) {
+            LOG(ERROR) << "Failed to get file stat for " << cur_file_path
+                       << ": " << strerror(errno);
+            n_error++;
+            continue;
+        }
+        const int fd_read = open(cur_file_path.c_str(), O_RDONLY);
+        if (fd_read == -1) {
+            LOG(ERROR) << "Failed to open file " << cur_file_path << " "
+                       << strerror(errno);
+            n_error++;
+            continue;
+        }
+        unique_fd file_auto_closer(fd_read);
+        if (!cpioWriteHeader(out_fd, st, cur_file_name.c_str(),
+                             file_name_len)) {
+            return ++n_error;
+        }
+        size_t write_error = cpioWriteFileContent(fd_read, out_fd, st);
+        if (write_error) {
+            return n_error + write_error;
+        }
+    }
+    if (!cpioWriteFileTrailer(out_fd)) {
+        return ++n_error;
+    }
+    return n_error;
+}
+
+// Helper function to create a non-const char*.
+std::vector<char> makeCharVec(const std::string& str) {
+    std::vector<char> vec(str.size() + 1);
+    vec.assign(str.begin(), str.end());
+    vec.push_back('\0');
+    return vec;
+}
+
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+using hidl_return_util::validateAndCallWithLock;
+
+WifiChip::WifiChip(
+    ChipId chip_id, const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+    const std::weak_ptr<mode_controller::WifiModeController> mode_controller,
+    const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags)
+    : chip_id_(chip_id),
+      legacy_hal_(legacy_hal),
+      mode_controller_(mode_controller),
+      feature_flags_(feature_flags),
+      is_valid_(true),
+      current_mode_id_(kInvalidModeId),
+      debug_ring_buffer_cb_registered_(false) {
+    populateModes();
+}
+
+void WifiChip::invalidate() {
+    invalidateAndRemoveAllIfaces();
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    is_valid_ = false;
+}
+
+bool WifiChip::isValid() { return is_valid_; }
+
+std::set<sp<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiChip::getId(getId_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getIdInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::registerEventCallback(
+    const sp<V1_0::IWifiChipEventCallback>& event_callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::registerEventCallbackInternal,
+                           hidl_status_cb, event_callback);
+}
+
+Return<void> WifiChip::getCapabilities(getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getAvailableModes(getAvailableModes_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getAvailableModesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::configureChip(ChipModeId mode_id,
+                                     configureChip_cb hidl_status_cb) {
+    return validateAndCallWithLock(
+        this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+        &WifiChip::configureChipInternal, hidl_status_cb, mode_id);
+}
+
+Return<void> WifiChip::getMode(getMode_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getModeInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::requestChipDebugInfo(
+    requestChipDebugInfo_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestChipDebugInfoInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::requestDriverDebugDump(
+    requestDriverDebugDump_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestDriverDebugDumpInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::requestFirmwareDebugDump(
+    requestFirmwareDebugDump_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::requestFirmwareDebugDumpInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::createApIface(createApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createApIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getApIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getApIface(const hidl_string& ifname,
+                                  getApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getApIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::removeApIface(const hidl_string& ifname,
+                                     removeApIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeApIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createNanIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getNanIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getNanIface(const hidl_string& ifname,
+                                   getNanIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getNanIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::removeNanIface(const hidl_string& ifname,
+                                      removeNanIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeNanIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::createP2pIface(createP2pIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createP2pIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getP2pIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getP2pIface(const hidl_string& ifname,
+                                   getP2pIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getP2pIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::removeP2pIface(const hidl_string& ifname,
+                                      removeP2pIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeP2pIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createStaIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getStaIfaceNamesInternal, hidl_status_cb);
+}
+
+Return<void> WifiChip::getStaIface(const hidl_string& ifname,
+                                   getStaIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getStaIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::removeStaIface(const hidl_string& ifname,
+                                      removeStaIface_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::removeStaIfaceInternal, hidl_status_cb,
+                           ifname);
+}
+
+Return<void> WifiChip::createRttController(
+    const sp<IWifiIface>& bound_iface, createRttController_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::createRttControllerInternal,
+                           hidl_status_cb, bound_iface);
+}
+
+Return<void> WifiChip::getDebugRingBuffersStatus(
+    getDebugRingBuffersStatus_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getDebugRingBuffersStatusInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::startLoggingToDebugRingBuffer(
+    const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+    uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
+    startLoggingToDebugRingBuffer_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::startLoggingToDebugRingBufferInternal,
+                           hidl_status_cb, ring_name, verbose_level,
+                           max_interval_in_sec, min_data_size_in_bytes);
+}
+
+Return<void> WifiChip::forceDumpToDebugRingBuffer(
+    const hidl_string& ring_name,
+    forceDumpToDebugRingBuffer_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::forceDumpToDebugRingBufferInternal,
+                           hidl_status_cb, ring_name);
+}
+
+Return<void> WifiChip::stopLoggingToDebugRingBuffer(
+    stopLoggingToDebugRingBuffer_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::stopLoggingToDebugRingBufferInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::getDebugHostWakeReasonStats(
+    getDebugHostWakeReasonStats_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::getDebugHostWakeReasonStatsInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::enableDebugErrorAlerts(
+    bool enable, enableDebugErrorAlerts_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::enableDebugErrorAlertsInternal,
+                           hidl_status_cb, enable);
+}
+
+Return<void> WifiChip::selectTxPowerScenario(
+    V1_1::IWifiChip::TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::selectTxPowerScenarioInternal,
+                           hidl_status_cb, scenario);
+}
+
+Return<void> WifiChip::resetTxPowerScenario(
+    resetTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::resetTxPowerScenarioInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiChip::registerEventCallback_1_2(
+    const sp<IWifiChipEventCallback>& event_callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                           &WifiChip::registerEventCallbackInternal_1_2,
+                           hidl_status_cb, event_callback);
+}
+
+Return<void> WifiChip::selectTxPowerScenario_1_2(
+        TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+            &WifiChip::selectTxPowerScenarioInternal_1_2, hidl_status_cb, scenario);
+}
+
+Return<void> WifiChip::debug(const hidl_handle& handle,
+                             const hidl_vec<hidl_string>&) {
+    if (handle != nullptr && handle->numFds >= 1) {
+        int fd = handle->data[0];
+        if (!writeRingbufferFilesInternal()) {
+            LOG(ERROR) << "Error writing files to flash";
+        }
+        uint32_t n_error = cpioArchiveFilesInDir(fd, kTombstoneFolderPath);
+        if (n_error != 0) {
+            LOG(ERROR) << n_error << " errors occured in cpio function";
+        }
+        fsync(fd);
+    } else {
+        LOG(ERROR) << "File handle error";
+    }
+    return Void();
+}
+
+void WifiChip::invalidateAndRemoveAllIfaces() {
+    invalidateAndClearAll(ap_ifaces_);
+    invalidateAndClearAll(nan_ifaces_);
+    invalidateAndClearAll(p2p_ifaces_);
+    invalidateAndClearAll(sta_ifaces_);
+    // Since all the ifaces are invalid now, all RTT controller objects
+    // using those ifaces also need to be invalidated.
+    for (const auto& rtt : rtt_controllers_) {
+        rtt->invalidate();
+    }
+    rtt_controllers_.clear();
+}
+
+std::pair<WifiStatus, ChipId> WifiChip::getIdInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), chip_id_};
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal(
+    const sp<V1_0::IWifiChipEventCallback>& /* event_callback */) {
+    // Deprecated support for this callback.
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    uint32_t legacy_feature_set;
+    uint32_t legacy_logger_feature_set;
+    std::tie(legacy_status, legacy_feature_set) =
+        legacy_hal_.lock()->getSupportedFeatureSet(getWlan0IfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), 0};
+    }
+    std::tie(legacy_status, legacy_logger_feature_set) =
+        legacy_hal_.lock()->getLoggerSupportedFeatureSet(getWlan0IfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        // some devices don't support querying logger feature set
+        legacy_logger_feature_set = 0;
+    }
+    uint32_t hidl_caps;
+    if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
+            legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, std::vector<IWifiChip::ChipMode>>
+WifiChip::getAvailableModesInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), modes_};
+}
+
+WifiStatus WifiChip::configureChipInternal(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+    ChipModeId mode_id) {
+    if (!isValidModeId(mode_id)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    if (mode_id == current_mode_id_) {
+        LOG(DEBUG) << "Already in the specified mode " << mode_id;
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    }
+    WifiStatus status = handleChipConfiguration(lock, mode_id);
+    if (status.code != WifiStatusCode::SUCCESS) {
+        for (const auto& callback : event_cb_handler_.getCallbacks()) {
+            if (!callback->onChipReconfigureFailure(status).isOk()) {
+                LOG(ERROR)
+                    << "Failed to invoke onChipReconfigureFailure callback";
+            }
+        }
+        return status;
+    }
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onChipReconfigured(mode_id).isOk()) {
+            LOG(ERROR) << "Failed to invoke onChipReconfigured callback";
+        }
+    }
+    current_mode_id_ = mode_id;
+    LOG(INFO) << "Configured chip in mode " << mode_id;
+    return status;
+}
+
+std::pair<WifiStatus, uint32_t> WifiChip::getModeInternal() {
+    if (!isValidModeId(current_mode_id_)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE),
+                current_mode_id_};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), current_mode_id_};
+}
+
+std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
+WifiChip::requestChipDebugInfoInternal() {
+    IWifiChip::ChipDebugInfo result;
+    legacy_hal::wifi_error legacy_status;
+    std::string driver_desc;
+    std::tie(legacy_status, driver_desc) =
+        legacy_hal_.lock()->getDriverVersion(getWlan0IfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get driver version: "
+                   << legacyErrorToString(legacy_status);
+        WifiStatus status = createWifiStatusFromLegacyError(
+            legacy_status, "failed to get driver version");
+        return {status, result};
+    }
+    result.driverDescription = driver_desc.c_str();
+
+    std::string firmware_desc;
+    std::tie(legacy_status, firmware_desc) =
+        legacy_hal_.lock()->getFirmwareVersion(getWlan0IfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get firmware version: "
+                   << legacyErrorToString(legacy_status);
+        WifiStatus status = createWifiStatusFromLegacyError(
+            legacy_status, "failed to get firmware version");
+        return {status, result};
+    }
+    result.firmwareDescription = firmware_desc.c_str();
+
+    return {createWifiStatus(WifiStatusCode::SUCCESS), result};
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>>
+WifiChip::requestDriverDebugDumpInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint8_t> driver_dump;
+    std::tie(legacy_status, driver_dump) =
+        legacy_hal_.lock()->requestDriverMemoryDump(getWlan0IfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get driver debug dump: "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status),
+                std::vector<uint8_t>()};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), driver_dump};
+}
+
+std::pair<WifiStatus, std::vector<uint8_t>>
+WifiChip::requestFirmwareDebugDumpInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint8_t> firmware_dump;
+    std::tie(legacy_status, firmware_dump) =
+        legacy_hal_.lock()->requestFirmwareMemoryDump(getWlan0IfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to get firmware debug dump: "
+                   << legacyErrorToString(legacy_status);
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
+}
+
+std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfType(IfaceType::AP)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::string ifname = allocateApOrStaIfaceName();
+    sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_);
+    ap_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::AP, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getApIfaceNamesInternal() {
+    if (ap_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(ap_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::getApIfaceInternal(
+    const std::string& ifname) {
+    const auto iface = findUsingName(ap_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeApIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(ap_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    invalidateAndClear(ap_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::createNanIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfType(IfaceType::NAN)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    // These are still assumed to be based on wlan0.
+    std::string ifname = getWlan0IfaceName();
+    sp<WifiNanIface> iface = new WifiNanIface(ifname, legacy_hal_);
+    nan_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::NAN, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getNanIfaceNamesInternal() {
+    if (nan_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(nan_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiNanIface>> WifiChip::getNanIfaceInternal(
+    const std::string& ifname) {
+    const auto iface = findUsingName(nan_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeNanIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(nan_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    invalidateAndClear(nan_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::NAN, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::createP2pIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfType(IfaceType::P2P)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::string ifname = getP2pIfaceName();
+    sp<WifiP2pIface> iface = new WifiP2pIface(ifname, legacy_hal_);
+    p2p_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::P2P, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getP2pIfaceNamesInternal() {
+    if (p2p_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(p2p_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiP2pIface>> WifiChip::getP2pIfaceInternal(
+    const std::string& ifname) {
+    const auto iface = findUsingName(p2p_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeP2pIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(p2p_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    invalidateAndClear(p2p_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::P2P, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {
+    if (!canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
+    std::string ifname = allocateApOrStaIfaceName();
+    sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_);
+    sta_ifaces_.push_back(iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
+        }
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, std::vector<hidl_string>>
+WifiChip::getStaIfaceNamesInternal() {
+    if (sta_ifaces_.empty()) {
+        return {createWifiStatus(WifiStatusCode::SUCCESS), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), getNames(sta_ifaces_)};
+}
+
+std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::getStaIfaceInternal(
+    const std::string& ifname) {
+    const auto iface = findUsingName(sta_ifaces_, ifname);
+    if (!iface.get()) {
+        return {createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS), nullptr};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+WifiStatus WifiChip::removeStaIfaceInternal(const std::string& ifname) {
+    const auto iface = findUsingName(sta_ifaces_, ifname);
+    if (!iface.get()) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    invalidateAndClear(sta_ifaces_, iface);
+    for (const auto& callback : event_cb_handler_.getCallbacks()) {
+        if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
+            LOG(ERROR) << "Failed to invoke onIfaceRemoved callback";
+        }
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, sp<IWifiRttController>>
+WifiChip::createRttControllerInternal(const sp<IWifiIface>& bound_iface) {
+    sp<WifiRttController> rtt =
+        new WifiRttController(getWlan0IfaceName(), bound_iface, legacy_hal_);
+    rtt_controllers_.emplace_back(rtt);
+    return {createWifiStatus(WifiStatusCode::SUCCESS), rtt};
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
+WifiChip::getDebugRingBuffersStatusInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_ring_buffer_status>
+        legacy_ring_buffer_status_vec;
+    std::tie(legacy_status, legacy_ring_buffer_status_vec) =
+        legacy_hal_.lock()->getRingBuffersStatus(getWlan0IfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    std::vector<WifiDebugRingBufferStatus> hidl_ring_buffer_status_vec;
+    if (!hidl_struct_util::convertLegacyVectorOfDebugRingBufferStatusToHidl(
+            legacy_ring_buffer_status_vec, &hidl_ring_buffer_status_vec)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS),
+            hidl_ring_buffer_status_vec};
+}
+
+WifiStatus WifiChip::startLoggingToDebugRingBufferInternal(
+    const hidl_string& ring_name, WifiDebugRingBufferVerboseLevel verbose_level,
+    uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes) {
+    WifiStatus status = registerDebugRingBufferCallback();
+    if (status.code != WifiStatusCode::SUCCESS) {
+        return status;
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->startRingBufferLogging(
+            getWlan0IfaceName(), ring_name,
+            static_cast<
+                std::underlying_type<WifiDebugRingBufferVerboseLevel>::type>(
+                verbose_level),
+            max_interval_in_sec, min_data_size_in_bytes);
+    ringbuffer_map_.insert(std::pair<std::string, Ringbuffer>(
+        ring_name, Ringbuffer(kMaxBufferSizeBytes)));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::forceDumpToDebugRingBufferInternal(
+    const hidl_string& ring_name) {
+    WifiStatus status = registerDebugRingBufferCallback();
+    if (status.code != WifiStatusCode::SUCCESS) {
+        return status;
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->getRingBufferData(getWlan0IfaceName(), ring_name);
+
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::stopLoggingToDebugRingBufferInternal() {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->deregisterRingBufferCallbackHandler(
+            getWlan0IfaceName());
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
+WifiChip::getDebugHostWakeReasonStatsInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::WakeReasonStats legacy_stats;
+    std::tie(legacy_status, legacy_stats) =
+        legacy_hal_.lock()->getWakeReasonStats(getWlan0IfaceName());
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    WifiDebugHostWakeReasonStats hidl_stats;
+    if (!hidl_struct_util::convertLegacyWakeReasonStatsToHidl(legacy_stats,
+                                                              &hidl_stats)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiChip::enableDebugErrorAlertsInternal(bool enable) {
+    legacy_hal::wifi_error legacy_status;
+    if (enable) {
+        android::wp<WifiChip> weak_ptr_this(this);
+        const auto& on_alert_callback = [weak_ptr_this](
+                                            int32_t error_code,
+                                            std::vector<uint8_t> debug_data) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onDebugErrorAlert(error_code, debug_data)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke onDebugErrorAlert callback";
+                }
+            }
+        };
+        legacy_status = legacy_hal_.lock()->registerErrorAlertCallbackHandler(
+            getWlan0IfaceName(), on_alert_callback);
+    } else {
+        legacy_status = legacy_hal_.lock()->deregisterErrorAlertCallbackHandler(
+            getWlan0IfaceName());
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal(
+        V1_1::IWifiChip::TxPowerScenario scenario) {
+    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+        getWlan0IfaceName(),
+        hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::resetTxPowerScenarioInternal() {
+    auto legacy_status =
+        legacy_hal_.lock()->resetTxPowerScenario(getWlan0IfaceName());
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::registerEventCallbackInternal_1_2(
+    const sp<IWifiChipEventCallback>& event_callback) {
+    if (!event_cb_handler_.addCallback(event_callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario) {
+    auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
+        getWlan0IfaceName(),
+        hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::handleChipConfiguration(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+    ChipModeId mode_id) {
+    // If the chip is already configured in a different mode, stop
+    // the legacy HAL and then start it after firmware mode change.
+    if (isValidModeId(current_mode_id_)) {
+        LOG(INFO) << "Reconfiguring chip from mode " << current_mode_id_
+                  << " to mode " << mode_id;
+        invalidateAndRemoveAllIfaces();
+        legacy_hal::wifi_error legacy_status =
+            legacy_hal_.lock()->stop(lock, []() {});
+        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+            LOG(ERROR) << "Failed to stop legacy HAL: "
+                       << legacyErrorToString(legacy_status);
+            return createWifiStatusFromLegacyError(legacy_status);
+        }
+    }
+    // Firmware mode change not needed for V2 devices.
+    bool success = true;
+    if (mode_id == kV1StaChipModeId) {
+        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::STA);
+    } else if (mode_id == kV1ApChipModeId) {
+        success = mode_controller_.lock()->changeFirmwareMode(IfaceType::AP);
+    }
+    if (!success) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->start();
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to start legacy HAL: "
+                   << legacyErrorToString(legacy_status);
+        return createWifiStatusFromLegacyError(legacy_status);
+    }
+    // Every time the HAL is restarted, we need to register the
+    // radio mode change callback.
+    WifiStatus status = registerRadioModeChangeCallback();
+    if (status.code != WifiStatusCode::SUCCESS) {
+        // This probably is not a critical failure?
+        LOG(ERROR) << "Failed to register radio mode change callback";
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiChip::registerDebugRingBufferCallback() {
+    if (debug_ring_buffer_cb_registered_) {
+        return createWifiStatus(WifiStatusCode::SUCCESS);
+    }
+
+    android::wp<WifiChip> weak_ptr_this(this);
+    const auto& on_ring_buffer_data_callback =
+        [weak_ptr_this](const std::string& name,
+                        const std::vector<uint8_t>& data,
+                        const legacy_hal::wifi_ring_buffer_status& status) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            WifiDebugRingBufferStatus hidl_status;
+            if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(
+                    status, &hidl_status)) {
+                LOG(ERROR) << "Error converting ring buffer status";
+                return;
+            }
+            const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
+            if (target != shared_ptr_this->ringbuffer_map_.end()) {
+                Ringbuffer& cur_buffer = target->second;
+                cur_buffer.append(data);
+            } else {
+                LOG(ERROR) << "Ringname " << name << " not found";
+                return;
+            }
+        };
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->registerRingBufferCallbackHandler(
+            getWlan0IfaceName(), on_ring_buffer_data_callback);
+
+    if (legacy_status == legacy_hal::WIFI_SUCCESS) {
+        debug_ring_buffer_cb_registered_ = true;
+    }
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiChip::registerRadioModeChangeCallback() {
+    android::wp<WifiChip> weak_ptr_this(this);
+    const auto& on_radio_mode_change_callback =
+        [weak_ptr_this](const std::vector<legacy_hal::WifiMacInfo>& mac_infos) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            std::vector<IWifiChipEventCallback::RadioModeInfo>
+                hidl_radio_mode_infos;
+            if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+                    mac_infos, &hidl_radio_mode_infos)) {
+                LOG(ERROR) << "Error converting wifi mac info";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onRadioModeChange(hidl_radio_mode_infos)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke onRadioModeChange"
+                               << " callback on: " << toString(callback);
+                }
+            }
+        };
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->registerRadioModeChangeCallbackHandler(
+            getWlan0IfaceName(), on_radio_mode_change_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+void WifiChip::populateModes() {
+    // The chip combination supported for current devices is fixed.
+    // They can be one of the following based on device features:
+    // a) 2 separate modes of operation with 1 interface combination each:
+    //    Mode 1 (STA mode): Will support 1 STA and 1 P2P or NAN(optional)
+    //                       concurrent iface operations.
+    //    Mode 2 (AP mode): Will support 1 AP iface operation.
+    //
+    // b) 1 mode of operation with 2 interface combinations
+    // (conditional on isDualInterfaceSupported()):
+    //    Interface Combination 1: Will support 1 STA and 1 P2P or NAN(optional)
+    //                             concurrent iface operations.
+    //    Interface Combination 2: Will support 1 STA and 1 STA or AP concurrent
+    //                             iface operations.
+    // If Aware is enabled (conditional on isAwareSupported()), the iface
+    // combination will be modified to support either P2P or NAN in place of
+    // just P2P.
+    if (feature_flags_.lock()->isDualInterfaceSupported()) {
+        // V2 Iface combinations for Mode Id = 2.
+        const IWifiChip::ChipIfaceCombinationLimit
+            chip_iface_combination_limit_1 = {{IfaceType::STA}, 1};
+        const IWifiChip::ChipIfaceCombinationLimit
+            chip_iface_combination_limit_2 = {{IfaceType::STA, IfaceType::AP},
+                                              1};
+        IWifiChip::ChipIfaceCombinationLimit chip_iface_combination_limit_3;
+        if (feature_flags_.lock()->isAwareSupported()) {
+            chip_iface_combination_limit_3 = {{IfaceType::P2P, IfaceType::NAN},
+                                              1};
+        } else {
+            chip_iface_combination_limit_3 = {{IfaceType::P2P}, 1};
+        }
+        const IWifiChip::ChipIfaceCombination chip_iface_combination_1 = {
+            {chip_iface_combination_limit_1, chip_iface_combination_limit_2}};
+        const IWifiChip::ChipIfaceCombination chip_iface_combination_2 = {
+            {chip_iface_combination_limit_1, chip_iface_combination_limit_3}};
+        const IWifiChip::ChipMode chip_mode = {
+            kV2ChipModeId,
+            {chip_iface_combination_1, chip_iface_combination_2}};
+        modes_ = {chip_mode};
+    } else {
+        // V1 Iface combinations for Mode Id = 0. (STA Mode)
+        const IWifiChip::ChipIfaceCombinationLimit
+            sta_chip_iface_combination_limit_1 = {{IfaceType::STA}, 1};
+        IWifiChip::ChipIfaceCombinationLimit sta_chip_iface_combination_limit_2;
+        if (feature_flags_.lock()->isAwareSupported()) {
+            sta_chip_iface_combination_limit_2 = {
+                {IfaceType::P2P, IfaceType::NAN}, 1};
+        } else {
+            sta_chip_iface_combination_limit_2 = {{IfaceType::P2P}, 1};
+        }
+        const IWifiChip::ChipIfaceCombination sta_chip_iface_combination = {
+            {sta_chip_iface_combination_limit_1,
+             sta_chip_iface_combination_limit_2}};
+        const IWifiChip::ChipMode sta_chip_mode = {
+            kV1StaChipModeId, {sta_chip_iface_combination}};
+        // Iface combinations for Mode Id = 1. (AP Mode)
+        const IWifiChip::ChipIfaceCombinationLimit
+            ap_chip_iface_combination_limit = {{IfaceType::AP}, 1};
+        const IWifiChip::ChipIfaceCombination ap_chip_iface_combination = {
+            {ap_chip_iface_combination_limit}};
+        const IWifiChip::ChipMode ap_chip_mode = {kV1ApChipModeId,
+                                                  {ap_chip_iface_combination}};
+        modes_ = {sta_chip_mode, ap_chip_mode};
+    }
+}
+
+std::vector<IWifiChip::ChipIfaceCombination>
+WifiChip::getCurrentModeIfaceCombinations() {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return {};
+    }
+    for (const auto& mode : modes_) {
+        if (mode.id == current_mode_id_) {
+            return mode.availableCombinations;
+        }
+    }
+    CHECK(0) << "Expected to find iface combinations for current mode!";
+    return {};
+}
+
+// Returns a map indexed by IfaceType with the number of ifaces currently
+// created of the corresponding type.
+std::map<IfaceType, size_t> WifiChip::getCurrentIfaceCombination() {
+    std::map<IfaceType, size_t> iface_counts;
+    iface_counts[IfaceType::AP] = ap_ifaces_.size();
+    iface_counts[IfaceType::NAN] = nan_ifaces_.size();
+    iface_counts[IfaceType::P2P] = p2p_ifaces_.size();
+    iface_counts[IfaceType::STA] = sta_ifaces_.size();
+    return iface_counts;
+}
+
+// This expands the provided iface combinations to a more parseable
+// form. Returns a vector of available combinations possible with the number
+// of ifaces of each type in the combination.
+// This method is a port of HalDeviceManager.expandIfaceCombos() from framework.
+std::vector<std::map<IfaceType, size_t>> WifiChip::expandIfaceCombinations(
+    const IWifiChip::ChipIfaceCombination& combination) {
+    uint32_t num_expanded_combos = 1;
+    for (const auto& limit : combination.limits) {
+        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+            num_expanded_combos *= limit.types.size();
+        }
+    }
+
+    // Allocate the vector of expanded combos and reset all iface counts to 0
+    // in each combo.
+    std::vector<std::map<IfaceType, size_t>> expanded_combos;
+    expanded_combos.resize(num_expanded_combos);
+    for (auto& expanded_combo : expanded_combos) {
+        for (const auto type :
+             {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+            expanded_combo[type] = 0;
+        }
+    }
+    uint32_t span = num_expanded_combos;
+    for (const auto& limit : combination.limits) {
+        for (uint32_t i = 0; i < limit.maxIfaces; i++) {
+            span /= limit.types.size();
+            for (uint32_t k = 0; k < num_expanded_combos; ++k) {
+                const auto iface_type =
+                    limit.types[(k / span) % limit.types.size()];
+                expanded_combos[k][iface_type]++;
+            }
+        }
+    }
+    return expanded_combos;
+}
+
+bool WifiChip::canExpandedIfaceCombinationSupportIfaceOfType(
+    const std::map<IfaceType, size_t>& combo, IfaceType requested_type) {
+    const auto current_combo = getCurrentIfaceCombination();
+
+    // Check if we have space for 1 more iface of |type| in this combo
+    for (const auto type :
+         {IfaceType::AP, IfaceType::NAN, IfaceType::P2P, IfaceType::STA}) {
+        size_t num_ifaces_needed = current_combo.at(type);
+        if (type == requested_type) {
+            num_ifaces_needed++;
+        }
+        size_t num_ifaces_allowed = combo.at(type);
+        if (num_ifaces_needed > num_ifaces_allowed) {
+            return false;
+        }
+    }
+    return true;
+}
+
+// This method does the following:
+// a) Enumerate all possible iface combos by expanding the current
+//    ChipIfaceCombination.
+// b) Check if the requested iface type can be added to the current mode.
+bool WifiChip::canCurrentModeSupportIfaceOfType(IfaceType type) {
+    if (!isValidModeId(current_mode_id_)) {
+        LOG(ERROR) << "Chip not configured in a mode yet";
+        return false;
+    }
+    const auto combinations = getCurrentModeIfaceCombinations();
+    for (const auto& combination : combinations) {
+        const auto expanded_combos = expandIfaceCombinations(combination);
+        for (const auto& expanded_combo : expanded_combos) {
+            if (canExpandedIfaceCombinationSupportIfaceOfType(expanded_combo,
+                                                              type)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+bool WifiChip::isValidModeId(ChipModeId mode_id) {
+    for (const auto& mode : modes_) {
+        if (mode.id == mode_id) {
+            return true;
+        }
+    }
+    return false;
+}
+
+// Return "wlan0", if "wlan0" is not already in use, else return "wlan1".
+// This is based on the assumption that we'll have a max of 2 concurrent
+// AP/STA ifaces.
+std::string WifiChip::allocateApOrStaIfaceName() {
+    auto ap_iface = findUsingName(ap_ifaces_, getWlan0IfaceName());
+    auto sta_iface = findUsingName(sta_ifaces_, getWlan0IfaceName());
+    if (!ap_iface.get() && !sta_iface.get()) {
+        return getWlan0IfaceName();
+    }
+    ap_iface = findUsingName(ap_ifaces_, getWlan1IfaceName());
+    sta_iface = findUsingName(sta_ifaces_, getWlan1IfaceName());
+    if (!ap_iface.get() && !sta_iface.get()) {
+        return getWlan1IfaceName();
+    }
+    // This should never happen. We screwed up somewhere if it did.
+    CHECK(0) << "wlan0 and wlan1 in use already!";
+    return {};
+}
+
+bool WifiChip::writeRingbufferFilesInternal() {
+    if (!removeOldFilesInternal()) {
+        LOG(ERROR) << "Error occurred while deleting old tombstone files";
+        return false;
+    }
+    // write ringbuffers to file
+    for (const auto& item : ringbuffer_map_) {
+        const Ringbuffer& cur_buffer = item.second;
+        if (cur_buffer.getData().empty()) {
+            continue;
+        }
+        const std::string file_path_raw =
+            kTombstoneFolderPath + item.first + "XXXXXXXXXX";
+        const int dump_fd = mkstemp(makeCharVec(file_path_raw).data());
+        if (dump_fd == -1) {
+            LOG(ERROR) << "create file failed: " << strerror(errno);
+            return false;
+        }
+        unique_fd file_auto_closer(dump_fd);
+        for (const auto& cur_block : cur_buffer.getData()) {
+            if (write(dump_fd, cur_block.data(),
+                      sizeof(cur_block[0]) * cur_block.size()) == -1) {
+                LOG(ERROR) << "Error writing to file " << strerror(errno);
+            }
+        }
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.2/default/wifi_chip.h
new file mode 100644
index 0000000..ada9458
--- /dev/null
+++ b/wifi/1.2/default/wifi_chip.h
@@ -0,0 +1,251 @@
+/*
+ * 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 WIFI_CHIP_H_
+#define WIFI_CHIP_H_
+
+#include <list>
+#include <map>
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.2/IWifiChip.h>
+
+#include "hidl_callback_util.h"
+#include "ringbuffer.h"
+#include "wifi_ap_iface.h"
+#include "wifi_feature_flags.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_mode_controller.h"
+#include "wifi_nan_iface.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_sta_iface.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a Wifi HAL chip instance.
+ * Since there is only a single chip instance used today, there is no
+ * identifying handle information stored here.
+ */
+class WifiChip : public V1_2::IWifiChip {
+   public:
+    WifiChip(
+        ChipId chip_id,
+        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
+        const std::weak_ptr<mode_controller::WifiModeController>
+            mode_controller,
+        const std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags);
+    // HIDL does not provide a built-in mechanism to let the server invalidate
+    // a HIDL interface object after creation. If any client process holds onto
+    // a reference to the object in their context, any method calls on that
+    // reference will continue to be directed to the server.
+    //
+    // However Wifi HAL needs to control the lifetime of these objects. So, add
+    // a public |invalidate| method to |WifiChip| and it's child objects. This
+    // will be used to mark an object invalid when either:
+    // a) Wifi HAL is stopped, or
+    // b) Wifi Chip is reconfigured.
+    //
+    // All HIDL method implementations should check if the object is still
+    // marked valid before processing them.
+    void invalidate();
+    bool isValid();
+    std::set<sp<IWifiChipEventCallback>> getEventCallbacks();
+
+    // HIDL methods exposed.
+    Return<void> getId(getId_cb hidl_status_cb) override;
+    Return<void> registerEventCallback(
+        const sp<V1_0::IWifiChipEventCallback>& event_callback,
+        registerEventCallback_cb hidl_status_cb) override;
+    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+    Return<void> getAvailableModes(
+        getAvailableModes_cb hidl_status_cb) override;
+    Return<void> configureChip(ChipModeId mode_id,
+                               configureChip_cb hidl_status_cb) override;
+    Return<void> getMode(getMode_cb hidl_status_cb) override;
+    Return<void> requestChipDebugInfo(
+        requestChipDebugInfo_cb hidl_status_cb) override;
+    Return<void> requestDriverDebugDump(
+        requestDriverDebugDump_cb hidl_status_cb) override;
+    Return<void> requestFirmwareDebugDump(
+        requestFirmwareDebugDump_cb hidl_status_cb) override;
+    Return<void> createApIface(createApIface_cb hidl_status_cb) override;
+    Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
+    Return<void> getApIface(const hidl_string& ifname,
+                            getApIface_cb hidl_status_cb) override;
+    Return<void> removeApIface(const hidl_string& ifname,
+                               removeApIface_cb hidl_status_cb) override;
+    Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
+    Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
+    Return<void> getNanIface(const hidl_string& ifname,
+                             getNanIface_cb hidl_status_cb) override;
+    Return<void> removeNanIface(const hidl_string& ifname,
+                                removeNanIface_cb hidl_status_cb) override;
+    Return<void> createP2pIface(createP2pIface_cb hidl_status_cb) override;
+    Return<void> getP2pIfaceNames(getP2pIfaceNames_cb hidl_status_cb) override;
+    Return<void> getP2pIface(const hidl_string& ifname,
+                             getP2pIface_cb hidl_status_cb) override;
+    Return<void> removeP2pIface(const hidl_string& ifname,
+                                removeP2pIface_cb hidl_status_cb) override;
+    Return<void> createStaIface(createStaIface_cb hidl_status_cb) override;
+    Return<void> getStaIfaceNames(getStaIfaceNames_cb hidl_status_cb) override;
+    Return<void> getStaIface(const hidl_string& ifname,
+                             getStaIface_cb hidl_status_cb) override;
+    Return<void> removeStaIface(const hidl_string& ifname,
+                                removeStaIface_cb hidl_status_cb) override;
+    Return<void> createRttController(
+        const sp<IWifiIface>& bound_iface,
+        createRttController_cb hidl_status_cb) override;
+    Return<void> getDebugRingBuffersStatus(
+        getDebugRingBuffersStatus_cb hidl_status_cb) override;
+    Return<void> startLoggingToDebugRingBuffer(
+        const hidl_string& ring_name,
+        WifiDebugRingBufferVerboseLevel verbose_level,
+        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes,
+        startLoggingToDebugRingBuffer_cb hidl_status_cb) override;
+    Return<void> forceDumpToDebugRingBuffer(
+        const hidl_string& ring_name,
+        forceDumpToDebugRingBuffer_cb hidl_status_cb) override;
+    Return<void> stopLoggingToDebugRingBuffer(
+        stopLoggingToDebugRingBuffer_cb hidl_status_cb) override;
+    Return<void> getDebugHostWakeReasonStats(
+        getDebugHostWakeReasonStats_cb hidl_status_cb) override;
+    Return<void> enableDebugErrorAlerts(
+        bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
+    Return<void> selectTxPowerScenario(
+        V1_1::IWifiChip::TxPowerScenario scenario,
+        selectTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> resetTxPowerScenario(
+        resetTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> registerEventCallback_1_2(
+        const sp<IWifiChipEventCallback>& event_callback,
+        registerEventCallback_1_2_cb hidl_status_cb) override;
+    Return<void> selectTxPowerScenario_1_2(
+        TxPowerScenario scenario,
+        selectTxPowerScenario_cb hidl_status_cb) override;
+    Return<void> debug(const hidl_handle& handle,
+                       const hidl_vec<hidl_string>& options) override;
+   private:
+    void invalidateAndRemoveAllIfaces();
+
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, ChipId> getIdInternal();
+    WifiStatus registerEventCallbackInternal(
+        const sp<V1_0::IWifiChipEventCallback>& event_callback);
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
+    std::pair<WifiStatus, std::vector<ChipMode>> getAvailableModesInternal();
+    WifiStatus configureChipInternal(
+        std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
+    std::pair<WifiStatus, uint32_t> getModeInternal();
+    std::pair<WifiStatus, IWifiChip::ChipDebugInfo>
+    requestChipDebugInfoInternal();
+    std::pair<WifiStatus, std::vector<uint8_t>>
+    requestDriverDebugDumpInternal();
+    std::pair<WifiStatus, std::vector<uint8_t>>
+    requestFirmwareDebugDumpInternal();
+    std::pair<WifiStatus, sp<IWifiApIface>> createApIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
+    std::pair<WifiStatus, sp<IWifiApIface>> getApIfaceInternal(
+        const std::string& ifname);
+    WifiStatus removeApIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<IWifiNanIface>> createNanIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
+    std::pair<WifiStatus, sp<IWifiNanIface>> getNanIfaceInternal(
+        const std::string& ifname);
+    WifiStatus removeNanIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<IWifiP2pIface>> createP2pIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getP2pIfaceNamesInternal();
+    std::pair<WifiStatus, sp<IWifiP2pIface>> getP2pIfaceInternal(
+        const std::string& ifname);
+    WifiStatus removeP2pIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<IWifiStaIface>> createStaIfaceInternal();
+    std::pair<WifiStatus, std::vector<hidl_string>> getStaIfaceNamesInternal();
+    std::pair<WifiStatus, sp<IWifiStaIface>> getStaIfaceInternal(
+        const std::string& ifname);
+    WifiStatus removeStaIfaceInternal(const std::string& ifname);
+    std::pair<WifiStatus, sp<IWifiRttController>> createRttControllerInternal(
+        const sp<IWifiIface>& bound_iface);
+    std::pair<WifiStatus, std::vector<WifiDebugRingBufferStatus>>
+    getDebugRingBuffersStatusInternal();
+    WifiStatus startLoggingToDebugRingBufferInternal(
+        const hidl_string& ring_name,
+        WifiDebugRingBufferVerboseLevel verbose_level,
+        uint32_t max_interval_in_sec, uint32_t min_data_size_in_bytes);
+    WifiStatus forceDumpToDebugRingBufferInternal(const hidl_string& ring_name);
+    WifiStatus stopLoggingToDebugRingBufferInternal();
+    std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
+    getDebugHostWakeReasonStatsInternal();
+    WifiStatus enableDebugErrorAlertsInternal(bool enable);
+    WifiStatus selectTxPowerScenarioInternal(V1_1::IWifiChip::TxPowerScenario scenario);
+    WifiStatus resetTxPowerScenarioInternal();
+    WifiStatus registerEventCallbackInternal_1_2(
+        const sp<IWifiChipEventCallback>& event_callback);
+    WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
+    WifiStatus handleChipConfiguration(
+        std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
+    WifiStatus registerDebugRingBufferCallback();
+    WifiStatus registerRadioModeChangeCallback();
+
+    void populateModes();
+    std::vector<IWifiChip::ChipIfaceCombination>
+    getCurrentModeIfaceCombinations();
+    std::map<IfaceType, size_t> getCurrentIfaceCombination();
+    std::vector<std::map<IfaceType, size_t>> expandIfaceCombinations(
+        const IWifiChip::ChipIfaceCombination& combination);
+    bool canExpandedIfaceCombinationSupportIfaceOfType(
+        const std::map<IfaceType, size_t>& combo, IfaceType type);
+    bool canCurrentModeSupportIfaceOfType(IfaceType type);
+    bool isValidModeId(ChipModeId mode_id);
+    std::string allocateApOrStaIfaceName();
+    bool writeRingbufferFilesInternal();
+
+    ChipId chip_id_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::weak_ptr<mode_controller::WifiModeController> mode_controller_;
+    std::weak_ptr<feature_flags::WifiFeatureFlags> feature_flags_;
+    std::vector<sp<WifiApIface>> ap_ifaces_;
+    std::vector<sp<WifiNanIface>> nan_ifaces_;
+    std::vector<sp<WifiP2pIface>> p2p_ifaces_;
+    std::vector<sp<WifiStaIface>> sta_ifaces_;
+    std::vector<sp<WifiRttController>> rtt_controllers_;
+    std::map<std::string, Ringbuffer> ringbuffer_map_;
+    bool is_valid_;
+    // Members pertaining to chip configuration.
+    uint32_t current_mode_id_;
+    std::vector<IWifiChip::ChipMode> modes_;
+    // The legacy ring buffer callback API has only a global callback
+    // registration mechanism. Use this to check if we have already
+    // registered a callback.
+    bool debug_ring_buffer_cb_registered_;
+    hidl_callback_util::HidlCallbackHandler<IWifiChipEventCallback>
+        event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiChip);
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_CHIP_H_
diff --git a/wifi/1.2/default/wifi_feature_flags.cpp b/wifi/1.2/default/wifi_feature_flags.cpp
new file mode 100644
index 0000000..554d4d5
--- /dev/null
+++ b/wifi/1.2/default/wifi_feature_flags.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#include "wifi_feature_flags.h"
+
+namespace {
+#ifdef WIFI_HIDL_FEATURE_AWARE
+static const bool wifiHidlFeatureAware = true;
+#else
+static const bool wifiHidlFeatureAware = false;
+#endif  // WIFI_HIDL_FEATURE_AWARE
+#ifdef WIFI_HIDL_FEATURE_DUAL_INTERFACE
+static const bool wifiHidlFeatureDualInterface = true;
+#else
+static const bool wifiHidlFeatureDualInterface = false;
+#endif  // WIFI_HIDL_FEATURE_DUAL_INTERFACE
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace feature_flags {
+
+WifiFeatureFlags::WifiFeatureFlags() {}
+bool WifiFeatureFlags::isAwareSupported() { return wifiHidlFeatureAware; }
+bool WifiFeatureFlags::isDualInterfaceSupported() {
+    return wifiHidlFeatureDualInterface;
+}
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_feature_flags.h b/wifi/1.2/default/wifi_feature_flags.h
new file mode 100644
index 0000000..dc0c1ff
--- /dev/null
+++ b/wifi/1.2/default/wifi_feature_flags.h
@@ -0,0 +1,43 @@
+/*
+ * 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 WIFI_FEATURE_FLAGS_H_
+#define WIFI_FEATURE_FLAGS_H_
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace feature_flags {
+
+class WifiFeatureFlags {
+   public:
+    WifiFeatureFlags();
+    virtual ~WifiFeatureFlags() = default;
+
+    virtual bool isAwareSupported();
+    virtual bool isDualInterfaceSupported();
+};
+
+}  // namespace feature_flags
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_FEATURE_FLAGS_H_
diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.2/default/wifi_legacy_hal.cpp
new file mode 100644
index 0000000..5f40d50
--- /dev/null
+++ b/wifi/1.2/default/wifi_legacy_hal.cpp
@@ -0,0 +1,1399 @@
+/*
+ * 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.
+ */
+
+#include <array>
+#include <chrono>
+
+#include <android-base/logging.h>
+
+#include "hidl_sync_util.h"
+#include "wifi_legacy_hal.h"
+#include "wifi_legacy_hal_stubs.h"
+
+namespace {
+// Constants ported over from the legacy HAL calling code
+// (com_android_server_wifi_WifiNative.cpp). This will all be thrown
+// away when this shim layer is replaced by the real vendor
+// implementation.
+static constexpr uint32_t kMaxVersionStringLength = 256;
+static constexpr uint32_t kMaxCachedGscanResults = 64;
+static constexpr uint32_t kMaxGscanFrequenciesForBand = 64;
+static constexpr uint32_t kLinkLayerStatsDataMpduSizeThreshold = 128;
+static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
+static constexpr uint32_t kMaxRingBuffers = 10;
+static constexpr uint32_t kMaxStopCompleteWaitMs = 100;
+
+// Helper function to create a non-const char* for legacy Hal API's.
+std::vector<char> makeCharVec(const std::string& str) {
+    std::vector<char> vec(str.size() + 1);
+    vec.assign(str.begin(), str.end());
+    vec.push_back('\0');
+    return vec;
+}
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace legacy_hal {
+// Legacy HAL functions accept "C" style function pointers, so use global
+// functions to pass to the legacy HAL function and store the corresponding
+// std::function methods to be invoked.
+//
+// Callback to be invoked once |stop| is complete
+std::function<void(wifi_handle handle)> on_stop_complete_internal_callback;
+void onAsyncStopComplete(wifi_handle handle) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_stop_complete_internal_callback) {
+        on_stop_complete_internal_callback(handle);
+        // Invalidate this callback since we don't want this firing again.
+        on_stop_complete_internal_callback = nullptr;
+    }
+}
+
+// Callback to be invoked for driver dump.
+std::function<void(char*, int)> on_driver_memory_dump_internal_callback;
+void onSyncDriverMemoryDump(char* buffer, int buffer_size) {
+    if (on_driver_memory_dump_internal_callback) {
+        on_driver_memory_dump_internal_callback(buffer, buffer_size);
+    }
+}
+
+// Callback to be invoked for firmware dump.
+std::function<void(char*, int)> on_firmware_memory_dump_internal_callback;
+void onSyncFirmwareMemoryDump(char* buffer, int buffer_size) {
+    if (on_firmware_memory_dump_internal_callback) {
+        on_firmware_memory_dump_internal_callback(buffer, buffer_size);
+    }
+}
+
+// Callback to be invoked for Gscan events.
+std::function<void(wifi_request_id, wifi_scan_event)>
+    on_gscan_event_internal_callback;
+void onAsyncGscanEvent(wifi_request_id id, wifi_scan_event event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_gscan_event_internal_callback) {
+        on_gscan_event_internal_callback(id, event);
+    }
+}
+
+// Callback to be invoked for Gscan full results.
+std::function<void(wifi_request_id, wifi_scan_result*, uint32_t)>
+    on_gscan_full_result_internal_callback;
+void onAsyncGscanFullResult(wifi_request_id id, wifi_scan_result* result,
+                            uint32_t buckets_scanned) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_gscan_full_result_internal_callback) {
+        on_gscan_full_result_internal_callback(id, result, buckets_scanned);
+    }
+}
+
+// Callback to be invoked for link layer stats results.
+std::function<void((wifi_request_id, wifi_iface_stat*, int, wifi_radio_stat*))>
+    on_link_layer_stats_result_internal_callback;
+void onSyncLinkLayerStatsResult(wifi_request_id id, wifi_iface_stat* iface_stat,
+                                int num_radios, wifi_radio_stat* radio_stat) {
+    if (on_link_layer_stats_result_internal_callback) {
+        on_link_layer_stats_result_internal_callback(id, iface_stat, num_radios,
+                                                     radio_stat);
+    }
+}
+
+// Callback to be invoked for rssi threshold breach.
+std::function<void((wifi_request_id, uint8_t*, int8_t))>
+    on_rssi_threshold_breached_internal_callback;
+void onAsyncRssiThresholdBreached(wifi_request_id id, uint8_t* bssid,
+                                  int8_t rssi) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_rssi_threshold_breached_internal_callback) {
+        on_rssi_threshold_breached_internal_callback(id, bssid, rssi);
+    }
+}
+
+// Callback to be invoked for ring buffer data indication.
+std::function<void(char*, char*, int, wifi_ring_buffer_status*)>
+    on_ring_buffer_data_internal_callback;
+void onAsyncRingBufferData(char* ring_name, char* buffer, int buffer_size,
+                           wifi_ring_buffer_status* status) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_ring_buffer_data_internal_callback) {
+        on_ring_buffer_data_internal_callback(ring_name, buffer, buffer_size,
+                                              status);
+    }
+}
+
+// Callback to be invoked for error alert indication.
+std::function<void(wifi_request_id, char*, int, int)>
+    on_error_alert_internal_callback;
+void onAsyncErrorAlert(wifi_request_id id, char* buffer, int buffer_size,
+                       int err_code) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_error_alert_internal_callback) {
+        on_error_alert_internal_callback(id, buffer, buffer_size, err_code);
+    }
+}
+
+// Callback to be invoked for radio mode change indication.
+std::function<void(wifi_request_id, uint32_t, wifi_mac_info*)>
+    on_radio_mode_change_internal_callback;
+void onAsyncRadioModeChange(wifi_request_id id, uint32_t num_macs,
+                            wifi_mac_info* mac_infos) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_radio_mode_change_internal_callback) {
+        on_radio_mode_change_internal_callback(id, num_macs, mac_infos);
+    }
+}
+
+// Callback to be invoked for rtt results results.
+std::function<void(wifi_request_id, unsigned num_results,
+                   wifi_rtt_result* rtt_results[])>
+    on_rtt_results_internal_callback;
+void onAsyncRttResults(wifi_request_id id, unsigned num_results,
+                       wifi_rtt_result* rtt_results[]) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_rtt_results_internal_callback) {
+        on_rtt_results_internal_callback(id, num_results, rtt_results);
+        on_rtt_results_internal_callback = nullptr;
+    }
+}
+
+// Callbacks for the various NAN operations.
+// NOTE: These have very little conversions to perform before invoking the user
+// callbacks.
+// So, handle all of them here directly to avoid adding an unnecessary layer.
+std::function<void(transaction_id, const NanResponseMsg&)>
+    on_nan_notify_response_user_callback;
+void onAysncNanNotifyResponse(transaction_id id, NanResponseMsg* msg) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_notify_response_user_callback && msg) {
+        on_nan_notify_response_user_callback(id, *msg);
+    }
+}
+
+std::function<void(const NanPublishRepliedInd&)>
+    on_nan_event_publish_replied_user_callback;
+void onAysncNanEventPublishReplied(NanPublishRepliedInd* /* event */) {
+    LOG(ERROR) << "onAysncNanEventPublishReplied triggered";
+}
+
+std::function<void(const NanPublishTerminatedInd&)>
+    on_nan_event_publish_terminated_user_callback;
+void onAysncNanEventPublishTerminated(NanPublishTerminatedInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_publish_terminated_user_callback && event) {
+        on_nan_event_publish_terminated_user_callback(*event);
+    }
+}
+
+std::function<void(const NanMatchInd&)> on_nan_event_match_user_callback;
+void onAysncNanEventMatch(NanMatchInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_match_user_callback && event) {
+        on_nan_event_match_user_callback(*event);
+    }
+}
+
+std::function<void(const NanMatchExpiredInd&)>
+    on_nan_event_match_expired_user_callback;
+void onAysncNanEventMatchExpired(NanMatchExpiredInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_match_expired_user_callback && event) {
+        on_nan_event_match_expired_user_callback(*event);
+    }
+}
+
+std::function<void(const NanSubscribeTerminatedInd&)>
+    on_nan_event_subscribe_terminated_user_callback;
+void onAysncNanEventSubscribeTerminated(NanSubscribeTerminatedInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_subscribe_terminated_user_callback && event) {
+        on_nan_event_subscribe_terminated_user_callback(*event);
+    }
+}
+
+std::function<void(const NanFollowupInd&)> on_nan_event_followup_user_callback;
+void onAysncNanEventFollowup(NanFollowupInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_followup_user_callback && event) {
+        on_nan_event_followup_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDiscEngEventInd&)>
+    on_nan_event_disc_eng_event_user_callback;
+void onAysncNanEventDiscEngEvent(NanDiscEngEventInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_disc_eng_event_user_callback && event) {
+        on_nan_event_disc_eng_event_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDisabledInd&)> on_nan_event_disabled_user_callback;
+void onAysncNanEventDisabled(NanDisabledInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_disabled_user_callback && event) {
+        on_nan_event_disabled_user_callback(*event);
+    }
+}
+
+std::function<void(const NanTCAInd&)> on_nan_event_tca_user_callback;
+void onAysncNanEventTca(NanTCAInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_tca_user_callback && event) {
+        on_nan_event_tca_user_callback(*event);
+    }
+}
+
+std::function<void(const NanBeaconSdfPayloadInd&)>
+    on_nan_event_beacon_sdf_payload_user_callback;
+void onAysncNanEventBeaconSdfPayload(NanBeaconSdfPayloadInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_beacon_sdf_payload_user_callback && event) {
+        on_nan_event_beacon_sdf_payload_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathRequestInd&)>
+    on_nan_event_data_path_request_user_callback;
+void onAysncNanEventDataPathRequest(NanDataPathRequestInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_request_user_callback && event) {
+        on_nan_event_data_path_request_user_callback(*event);
+    }
+}
+std::function<void(const NanDataPathConfirmInd&)>
+    on_nan_event_data_path_confirm_user_callback;
+void onAysncNanEventDataPathConfirm(NanDataPathConfirmInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_confirm_user_callback && event) {
+        on_nan_event_data_path_confirm_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathEndInd&)>
+    on_nan_event_data_path_end_user_callback;
+void onAysncNanEventDataPathEnd(NanDataPathEndInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_data_path_end_user_callback && event) {
+        on_nan_event_data_path_end_user_callback(*event);
+    }
+}
+
+std::function<void(const NanTransmitFollowupInd&)>
+    on_nan_event_transmit_follow_up_user_callback;
+void onAysncNanEventTransmitFollowUp(NanTransmitFollowupInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_transmit_follow_up_user_callback && event) {
+        on_nan_event_transmit_follow_up_user_callback(*event);
+    }
+}
+
+std::function<void(const NanRangeRequestInd&)>
+    on_nan_event_range_request_user_callback;
+void onAysncNanEventRangeRequest(NanRangeRequestInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_range_request_user_callback && event) {
+        on_nan_event_range_request_user_callback(*event);
+    }
+}
+
+std::function<void(const NanRangeReportInd&)>
+    on_nan_event_range_report_user_callback;
+void onAysncNanEventRangeReport(NanRangeReportInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_range_report_user_callback && event) {
+        on_nan_event_range_report_user_callback(*event);
+    }
+}
+
+std::function<void(const NanDataPathScheduleUpdateInd&)>
+    on_nan_event_schedule_update_user_callback;
+void onAsyncNanEventScheduleUpdate(NanDataPathScheduleUpdateInd* event) {
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (on_nan_event_schedule_update_user_callback && event) {
+        on_nan_event_schedule_update_user_callback(*event);
+    }
+}
+// End of the free-standing "C" style callbacks.
+
+WifiLegacyHal::WifiLegacyHal()
+    : global_handle_(nullptr),
+      awaiting_event_loop_termination_(false),
+      is_started_(false) {}
+
+wifi_error WifiLegacyHal::initialize() {
+    LOG(DEBUG) << "Initialize legacy HAL";
+    // TODO: Add back the HAL Tool if we need to. All we need from the HAL tool
+    // for now is this function call which we can directly call.
+    if (!initHalFuncTableWithStubs(&global_func_table_)) {
+        LOG(ERROR)
+            << "Failed to initialize legacy hal function table with stubs";
+        return WIFI_ERROR_UNKNOWN;
+    }
+    wifi_error status = init_wifi_vendor_hal_func_table(&global_func_table_);
+    if (status != WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to initialize legacy hal function table";
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::start() {
+    // Ensure that we're starting in a good state.
+    CHECK(global_func_table_.wifi_initialize && !global_handle_ &&
+          iface_name_to_handle_.empty() && !awaiting_event_loop_termination_);
+    if (is_started_) {
+        LOG(DEBUG) << "Legacy HAL already started";
+        return WIFI_SUCCESS;
+    }
+    LOG(DEBUG) << "Starting legacy HAL";
+    if (!iface_tool_.SetWifiUpState(true)) {
+        LOG(ERROR) << "Failed to set WiFi interface up";
+        return WIFI_ERROR_UNKNOWN;
+    }
+    wifi_error status = global_func_table_.wifi_initialize(&global_handle_);
+    if (status != WIFI_SUCCESS || !global_handle_) {
+        LOG(ERROR) << "Failed to retrieve global handle";
+        return status;
+    }
+    std::thread(&WifiLegacyHal::runEventLoop, this).detach();
+    status = retrieveIfaceHandles();
+    if (status != WIFI_SUCCESS || iface_name_to_handle_.empty()) {
+        LOG(ERROR) << "Failed to retrieve wlan interface handle";
+        return status;
+    }
+    LOG(DEBUG) << "Legacy HAL start complete";
+    is_started_ = true;
+    return WIFI_SUCCESS;
+}
+
+wifi_error WifiLegacyHal::stop(
+    /* NONNULL */ std::unique_lock<std::recursive_mutex>* lock,
+    const std::function<void()>& on_stop_complete_user_callback) {
+    if (!is_started_) {
+        LOG(DEBUG) << "Legacy HAL already stopped";
+        on_stop_complete_user_callback();
+        return WIFI_SUCCESS;
+    }
+    LOG(DEBUG) << "Stopping legacy HAL";
+    on_stop_complete_internal_callback = [on_stop_complete_user_callback,
+                                          this](wifi_handle handle) {
+        CHECK_EQ(global_handle_, handle) << "Handle mismatch";
+        LOG(INFO) << "Legacy HAL stop complete callback received";
+        // Invalidate all the internal pointers now that the HAL is
+        // stopped.
+        invalidate();
+        iface_tool_.SetWifiUpState(false);
+        on_stop_complete_user_callback();
+        is_started_ = false;
+    };
+    awaiting_event_loop_termination_ = true;
+    global_func_table_.wifi_cleanup(global_handle_, onAsyncStopComplete);
+    const auto status = stop_wait_cv_.wait_for(
+        *lock, std::chrono::milliseconds(kMaxStopCompleteWaitMs),
+        [this] { return !awaiting_event_loop_termination_; });
+    if (!status) {
+        LOG(ERROR) << "Legacy HAL stop failed or timed out";
+        return WIFI_ERROR_UNKNOWN;
+    }
+    LOG(DEBUG) << "Legacy HAL stop complete";
+    return WIFI_SUCCESS;
+}
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getDriverVersion(
+    const std::string& iface_name) {
+    std::array<char, kMaxVersionStringLength> buffer;
+    buffer.fill(0);
+    wifi_error status = global_func_table_.wifi_get_driver_version(
+        getIfaceHandle(iface_name), buffer.data(), buffer.size());
+    return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::string> WifiLegacyHal::getFirmwareVersion(
+    const std::string& iface_name) {
+    std::array<char, kMaxVersionStringLength> buffer;
+    buffer.fill(0);
+    wifi_error status = global_func_table_.wifi_get_firmware_version(
+        getIfaceHandle(iface_name), buffer.data(), buffer.size());
+    return {status, buffer.data()};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>>
+WifiLegacyHal::requestDriverMemoryDump(const std::string& iface_name) {
+    std::vector<uint8_t> driver_dump;
+    on_driver_memory_dump_internal_callback = [&driver_dump](char* buffer,
+                                                             int buffer_size) {
+        driver_dump.insert(driver_dump.end(),
+                           reinterpret_cast<uint8_t*>(buffer),
+                           reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+    };
+    wifi_error status = global_func_table_.wifi_get_driver_memory_dump(
+        getIfaceHandle(iface_name), {onSyncDriverMemoryDump});
+    on_driver_memory_dump_internal_callback = nullptr;
+    return {status, std::move(driver_dump)};
+}
+
+std::pair<wifi_error, std::vector<uint8_t>>
+WifiLegacyHal::requestFirmwareMemoryDump(const std::string& iface_name) {
+    std::vector<uint8_t> firmware_dump;
+    on_firmware_memory_dump_internal_callback =
+        [&firmware_dump](char* buffer, int buffer_size) {
+            firmware_dump.insert(
+                firmware_dump.end(), reinterpret_cast<uint8_t*>(buffer),
+                reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+        };
+    wifi_error status = global_func_table_.wifi_get_firmware_memory_dump(
+        getIfaceHandle(iface_name), {onSyncFirmwareMemoryDump});
+    on_firmware_memory_dump_internal_callback = nullptr;
+    return {status, std::move(firmware_dump)};
+}
+
+std::pair<wifi_error, uint32_t> WifiLegacyHal::getSupportedFeatureSet(
+    const std::string& iface_name) {
+    feature_set set;
+    static_assert(sizeof(set) == sizeof(uint32_t),
+                  "Some feature_flags can not be represented in output");
+    wifi_error status = global_func_table_.wifi_get_supported_feature_set(
+        getIfaceHandle(iface_name), &set);
+    return {status, static_cast<uint32_t>(set)};
+}
+
+std::pair<wifi_error, PacketFilterCapabilities>
+WifiLegacyHal::getPacketFilterCapabilities(const std::string& iface_name) {
+    PacketFilterCapabilities caps;
+    wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+        getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::setPacketFilter(const std::string& iface_name,
+                                          const std::vector<uint8_t>& program) {
+    return global_func_table_.wifi_set_packet_filter(
+        getIfaceHandle(iface_name), program.data(), program.size());
+}
+
+std::pair<wifi_error, wifi_gscan_capabilities>
+WifiLegacyHal::getGscanCapabilities(const std::string& iface_name) {
+    wifi_gscan_capabilities caps;
+    wifi_error status = global_func_table_.wifi_get_gscan_capabilities(
+        getIfaceHandle(iface_name), &caps);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::startGscan(
+    const std::string& iface_name, wifi_request_id id,
+    const wifi_scan_cmd_params& params,
+    const std::function<void(wifi_request_id)>& on_failure_user_callback,
+    const on_gscan_results_callback& on_results_user_callback,
+    const on_gscan_full_result_callback& on_full_result_user_callback) {
+    // If there is already an ongoing background scan, reject new scan requests.
+    if (on_gscan_event_internal_callback ||
+        on_gscan_full_result_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    // This callback will be used to either trigger |on_results_user_callback|
+    // or |on_failure_user_callback|.
+    on_gscan_event_internal_callback =
+        [iface_name, on_failure_user_callback, on_results_user_callback, this](
+            wifi_request_id id, wifi_scan_event event) {
+            switch (event) {
+                case WIFI_SCAN_RESULTS_AVAILABLE:
+                case WIFI_SCAN_THRESHOLD_NUM_SCANS:
+                case WIFI_SCAN_THRESHOLD_PERCENT: {
+                    wifi_error status;
+                    std::vector<wifi_cached_scan_results> cached_scan_results;
+                    std::tie(status, cached_scan_results) =
+                        getGscanCachedResults(iface_name);
+                    if (status == WIFI_SUCCESS) {
+                        on_results_user_callback(id, cached_scan_results);
+                        return;
+                    }
+                }
+                // Fall through if failed. Failure to retrieve cached scan
+                // results should trigger a background scan failure.
+                case WIFI_SCAN_FAILED:
+                    on_failure_user_callback(id);
+                    on_gscan_event_internal_callback = nullptr;
+                    on_gscan_full_result_internal_callback = nullptr;
+                    return;
+            }
+            LOG(FATAL) << "Unexpected gscan event received: " << event;
+        };
+
+    on_gscan_full_result_internal_callback = [on_full_result_user_callback](
+                                                 wifi_request_id id,
+                                                 wifi_scan_result* result,
+                                                 uint32_t buckets_scanned) {
+        if (result) {
+            on_full_result_user_callback(id, result, buckets_scanned);
+        }
+    };
+
+    wifi_scan_result_handler handler = {onAsyncGscanFullResult,
+                                        onAsyncGscanEvent};
+    wifi_error status = global_func_table_.wifi_start_gscan(
+        id, getIfaceHandle(iface_name), params, handler);
+    if (status != WIFI_SUCCESS) {
+        on_gscan_event_internal_callback = nullptr;
+        on_gscan_full_result_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::stopGscan(const std::string& iface_name,
+                                    wifi_request_id id) {
+    // If there is no an ongoing background scan, reject stop requests.
+    // TODO(b/32337212): This needs to be handled by the HIDL object because we
+    // need to return the NOT_STARTED error code.
+    if (!on_gscan_event_internal_callback &&
+        !on_gscan_full_result_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    wifi_error status =
+        global_func_table_.wifi_stop_gscan(id, getIfaceHandle(iface_name));
+    // If the request Id is wrong, don't stop the ongoing background scan. Any
+    // other error should be treated as the end of background scan.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_gscan_event_internal_callback = nullptr;
+        on_gscan_full_result_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, std::vector<uint32_t>>
+WifiLegacyHal::getValidFrequenciesForBand(const std::string& iface_name,
+                                          wifi_band band) {
+    static_assert(sizeof(uint32_t) >= sizeof(wifi_channel),
+                  "Wifi Channel cannot be represented in output");
+    std::vector<uint32_t> freqs;
+    freqs.resize(kMaxGscanFrequenciesForBand);
+    int32_t num_freqs = 0;
+    wifi_error status = global_func_table_.wifi_get_valid_channels(
+        getIfaceHandle(iface_name), band, freqs.size(),
+        reinterpret_cast<wifi_channel*>(freqs.data()), &num_freqs);
+    CHECK(num_freqs >= 0 &&
+          static_cast<uint32_t>(num_freqs) <= kMaxGscanFrequenciesForBand);
+    freqs.resize(num_freqs);
+    return {status, std::move(freqs)};
+}
+
+wifi_error WifiLegacyHal::setDfsFlag(const std::string& iface_name,
+                                     bool dfs_on) {
+    return global_func_table_.wifi_set_nodfs_flag(getIfaceHandle(iface_name),
+                                                  dfs_on ? 0 : 1);
+}
+
+wifi_error WifiLegacyHal::enableLinkLayerStats(const std::string& iface_name,
+                                               bool debug) {
+    wifi_link_layer_params params;
+    params.mpdu_size_threshold = kLinkLayerStatsDataMpduSizeThreshold;
+    params.aggressive_statistics_gathering = debug;
+    return global_func_table_.wifi_set_link_stats(getIfaceHandle(iface_name),
+                                                  params);
+}
+
+wifi_error WifiLegacyHal::disableLinkLayerStats(const std::string& iface_name) {
+    // TODO: Do we care about these responses?
+    uint32_t clear_mask_rsp;
+    uint8_t stop_rsp;
+    return global_func_table_.wifi_clear_link_stats(
+        getIfaceHandle(iface_name), 0xFFFFFFFF, &clear_mask_rsp, 1, &stop_rsp);
+}
+
+std::pair<wifi_error, LinkLayerStats> WifiLegacyHal::getLinkLayerStats(
+    const std::string& iface_name) {
+    LinkLayerStats link_stats{};
+    LinkLayerStats* link_stats_ptr = &link_stats;
+
+    on_link_layer_stats_result_internal_callback =
+        [&link_stats_ptr](wifi_request_id /* id */,
+                          wifi_iface_stat* iface_stats_ptr, int num_radios,
+                          wifi_radio_stat* radio_stats_ptr) {
+            if (iface_stats_ptr != nullptr) {
+                link_stats_ptr->iface = *iface_stats_ptr;
+                link_stats_ptr->iface.num_peers = 0;
+            } else {
+                LOG(ERROR) << "Invalid iface stats in link layer stats";
+            }
+            if (num_radios <= 0 || radio_stats_ptr == nullptr) {
+                LOG(ERROR) << "Invalid radio stats in link layer stats";
+                return;
+            }
+            for (int i = 0; i < num_radios; i++) {
+                LinkLayerRadioStats radio;
+                radio.stats = radio_stats_ptr[i];
+                // Copy over the tx level array to the separate vector.
+                if (radio_stats_ptr[i].num_tx_levels > 0 &&
+                    radio_stats_ptr[i].tx_time_per_levels != nullptr) {
+                    radio.tx_time_per_levels.assign(
+                        radio_stats_ptr[i].tx_time_per_levels,
+                        radio_stats_ptr[i].tx_time_per_levels +
+                            radio_stats_ptr[i].num_tx_levels);
+                }
+                radio.stats.num_tx_levels = 0;
+                radio.stats.tx_time_per_levels = nullptr;
+                link_stats_ptr->radios.push_back(radio);
+            }
+        };
+
+    wifi_error status = global_func_table_.wifi_get_link_stats(
+        0, getIfaceHandle(iface_name), {onSyncLinkLayerStatsResult});
+    on_link_layer_stats_result_internal_callback = nullptr;
+    return {status, link_stats};
+}
+
+wifi_error WifiLegacyHal::startRssiMonitoring(
+    const std::string& iface_name, wifi_request_id id, int8_t max_rssi,
+    int8_t min_rssi,
+    const on_rssi_threshold_breached_callback&
+        on_threshold_breached_user_callback) {
+    if (on_rssi_threshold_breached_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_rssi_threshold_breached_internal_callback =
+        [on_threshold_breached_user_callback](wifi_request_id id,
+                                              uint8_t* bssid_ptr, int8_t rssi) {
+            if (!bssid_ptr) {
+                return;
+            }
+            std::array<uint8_t, 6> bssid_arr;
+            // |bssid_ptr| pointer is assumed to have 6 bytes for the mac
+            // address.
+            std::copy(bssid_ptr, bssid_ptr + 6, std::begin(bssid_arr));
+            on_threshold_breached_user_callback(id, bssid_arr, rssi);
+        };
+    wifi_error status = global_func_table_.wifi_start_rssi_monitoring(
+        id, getIfaceHandle(iface_name), max_rssi, min_rssi,
+        {onAsyncRssiThresholdBreached});
+    if (status != WIFI_SUCCESS) {
+        on_rssi_threshold_breached_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::stopRssiMonitoring(const std::string& iface_name,
+                                             wifi_request_id id) {
+    if (!on_rssi_threshold_breached_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    wifi_error status = global_func_table_.wifi_stop_rssi_monitoring(
+        id, getIfaceHandle(iface_name));
+    // If the request Id is wrong, don't stop the ongoing rssi monitoring. Any
+    // other error should be treated as the end of background scan.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_rssi_threshold_breached_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, wifi_roaming_capabilities>
+WifiLegacyHal::getRoamingCapabilities(const std::string& iface_name) {
+    wifi_roaming_capabilities caps;
+    wifi_error status = global_func_table_.wifi_get_roaming_capabilities(
+        getIfaceHandle(iface_name), &caps);
+    return {status, caps};
+}
+
+wifi_error WifiLegacyHal::configureRoaming(const std::string& iface_name,
+                                           const wifi_roaming_config& config) {
+    wifi_roaming_config config_internal = config;
+    return global_func_table_.wifi_configure_roaming(getIfaceHandle(iface_name),
+                                                     &config_internal);
+}
+
+wifi_error WifiLegacyHal::enableFirmwareRoaming(const std::string& iface_name,
+                                                fw_roaming_state_t state) {
+    return global_func_table_.wifi_enable_firmware_roaming(
+        getIfaceHandle(iface_name), state);
+}
+
+wifi_error WifiLegacyHal::configureNdOffload(const std::string& iface_name,
+                                             bool enable) {
+    return global_func_table_.wifi_configure_nd_offload(
+        getIfaceHandle(iface_name), enable);
+}
+
+wifi_error WifiLegacyHal::startSendingOffloadedPacket(
+    const std::string& iface_name, uint32_t cmd_id,
+    const std::vector<uint8_t>& ip_packet_data,
+    const std::array<uint8_t, 6>& src_address,
+    const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
+    std::vector<uint8_t> ip_packet_data_internal(ip_packet_data);
+    std::vector<uint8_t> src_address_internal(
+        src_address.data(), src_address.data() + src_address.size());
+    std::vector<uint8_t> dst_address_internal(
+        dst_address.data(), dst_address.data() + dst_address.size());
+    return global_func_table_.wifi_start_sending_offloaded_packet(
+        cmd_id, getIfaceHandle(iface_name), ip_packet_data_internal.data(),
+        ip_packet_data_internal.size(), src_address_internal.data(),
+        dst_address_internal.data(), period_in_ms);
+}
+
+wifi_error WifiLegacyHal::stopSendingOffloadedPacket(
+    const std::string& iface_name, uint32_t cmd_id) {
+    return global_func_table_.wifi_stop_sending_offloaded_packet(
+        cmd_id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setScanningMacOui(const std::string& iface_name,
+                                            const std::array<uint8_t, 3>& oui) {
+    std::vector<uint8_t> oui_internal(oui.data(), oui.data() + oui.size());
+    return global_func_table_.wifi_set_scanning_mac_oui(
+        getIfaceHandle(iface_name), oui_internal.data());
+}
+
+wifi_error WifiLegacyHal::selectTxPowerScenario(const std::string& iface_name,
+                                                wifi_power_scenario scenario) {
+    return global_func_table_.wifi_select_tx_power_scenario(
+        getIfaceHandle(iface_name), scenario);
+}
+
+wifi_error WifiLegacyHal::resetTxPowerScenario(const std::string& iface_name) {
+    return global_func_table_.wifi_reset_tx_power_scenario(
+        getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, uint32_t> WifiLegacyHal::getLoggerSupportedFeatureSet(
+    const std::string& iface_name) {
+    uint32_t supported_feature_flags;
+    wifi_error status =
+        global_func_table_.wifi_get_logger_supported_feature_set(
+            getIfaceHandle(iface_name), &supported_feature_flags);
+    return {status, supported_feature_flags};
+}
+
+wifi_error WifiLegacyHal::startPktFateMonitoring(
+    const std::string& iface_name) {
+    return global_func_table_.wifi_start_pkt_fate_monitoring(
+        getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_tx_report>> WifiLegacyHal::getTxPktFates(
+    const std::string& iface_name) {
+    std::vector<wifi_tx_report> tx_pkt_fates;
+    tx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+    size_t num_fates = 0;
+    wifi_error status = global_func_table_.wifi_get_tx_pkt_fates(
+        getIfaceHandle(iface_name), tx_pkt_fates.data(), tx_pkt_fates.size(),
+        &num_fates);
+    CHECK(num_fates <= MAX_FATE_LOG_LEN);
+    tx_pkt_fates.resize(num_fates);
+    return {status, std::move(tx_pkt_fates)};
+}
+
+std::pair<wifi_error, std::vector<wifi_rx_report>> WifiLegacyHal::getRxPktFates(
+    const std::string& iface_name) {
+    std::vector<wifi_rx_report> rx_pkt_fates;
+    rx_pkt_fates.resize(MAX_FATE_LOG_LEN);
+    size_t num_fates = 0;
+    wifi_error status = global_func_table_.wifi_get_rx_pkt_fates(
+        getIfaceHandle(iface_name), rx_pkt_fates.data(), rx_pkt_fates.size(),
+        &num_fates);
+    CHECK(num_fates <= MAX_FATE_LOG_LEN);
+    rx_pkt_fates.resize(num_fates);
+    return {status, std::move(rx_pkt_fates)};
+}
+
+std::pair<wifi_error, WakeReasonStats> WifiLegacyHal::getWakeReasonStats(
+    const std::string& iface_name) {
+    WakeReasonStats stats;
+    stats.cmd_event_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+    stats.driver_fw_local_wake_cnt.resize(kMaxWakeReasonStatsArraySize);
+
+    // This legacy struct needs separate memory to store the variable sized wake
+    // reason types.
+    stats.wake_reason_cnt.cmd_event_wake_cnt =
+        reinterpret_cast<int32_t*>(stats.cmd_event_wake_cnt.data());
+    stats.wake_reason_cnt.cmd_event_wake_cnt_sz =
+        stats.cmd_event_wake_cnt.size();
+    stats.wake_reason_cnt.cmd_event_wake_cnt_used = 0;
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt =
+        reinterpret_cast<int32_t*>(stats.driver_fw_local_wake_cnt.data());
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt_sz =
+        stats.driver_fw_local_wake_cnt.size();
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
+
+    wifi_error status = global_func_table_.wifi_get_wake_reason_stats(
+        getIfaceHandle(iface_name), &stats.wake_reason_cnt);
+
+    CHECK(
+        stats.wake_reason_cnt.cmd_event_wake_cnt_used >= 0 &&
+        static_cast<uint32_t>(stats.wake_reason_cnt.cmd_event_wake_cnt_used) <=
+            kMaxWakeReasonStatsArraySize);
+    stats.cmd_event_wake_cnt.resize(
+        stats.wake_reason_cnt.cmd_event_wake_cnt_used);
+    stats.wake_reason_cnt.cmd_event_wake_cnt = nullptr;
+
+    CHECK(stats.wake_reason_cnt.driver_fw_local_wake_cnt_used >= 0 &&
+          static_cast<uint32_t>(
+              stats.wake_reason_cnt.driver_fw_local_wake_cnt_used) <=
+              kMaxWakeReasonStatsArraySize);
+    stats.driver_fw_local_wake_cnt.resize(
+        stats.wake_reason_cnt.driver_fw_local_wake_cnt_used);
+    stats.wake_reason_cnt.driver_fw_local_wake_cnt = nullptr;
+
+    return {status, stats};
+}
+
+wifi_error WifiLegacyHal::registerRingBufferCallbackHandler(
+    const std::string& iface_name,
+    const on_ring_buffer_data_callback& on_user_data_callback) {
+    if (on_ring_buffer_data_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_ring_buffer_data_internal_callback =
+        [on_user_data_callback](char* ring_name, char* buffer, int buffer_size,
+                                wifi_ring_buffer_status* status) {
+            if (status && buffer) {
+                std::vector<uint8_t> buffer_vector(
+                    reinterpret_cast<uint8_t*>(buffer),
+                    reinterpret_cast<uint8_t*>(buffer) + buffer_size);
+                on_user_data_callback(ring_name, buffer_vector, *status);
+            }
+        };
+    wifi_error status = global_func_table_.wifi_set_log_handler(
+        0, getIfaceHandle(iface_name), {onAsyncRingBufferData});
+    if (status != WIFI_SUCCESS) {
+        on_ring_buffer_data_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::deregisterRingBufferCallbackHandler(
+    const std::string& iface_name) {
+    if (!on_ring_buffer_data_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_ring_buffer_data_internal_callback = nullptr;
+    return global_func_table_.wifi_reset_log_handler(
+        0, getIfaceHandle(iface_name));
+}
+
+std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
+WifiLegacyHal::getRingBuffersStatus(const std::string& iface_name) {
+    std::vector<wifi_ring_buffer_status> ring_buffers_status;
+    ring_buffers_status.resize(kMaxRingBuffers);
+    uint32_t num_rings = kMaxRingBuffers;
+    wifi_error status = global_func_table_.wifi_get_ring_buffers_status(
+        getIfaceHandle(iface_name), &num_rings, ring_buffers_status.data());
+    CHECK(num_rings <= kMaxRingBuffers);
+    ring_buffers_status.resize(num_rings);
+    return {status, std::move(ring_buffers_status)};
+}
+
+wifi_error WifiLegacyHal::startRingBufferLogging(const std::string& iface_name,
+                                                 const std::string& ring_name,
+                                                 uint32_t verbose_level,
+                                                 uint32_t max_interval_sec,
+                                                 uint32_t min_data_size) {
+    return global_func_table_.wifi_start_logging(
+        getIfaceHandle(iface_name), verbose_level, 0, max_interval_sec,
+        min_data_size, makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::getRingBufferData(const std::string& iface_name,
+                                            const std::string& ring_name) {
+    return global_func_table_.wifi_get_ring_data(getIfaceHandle(iface_name),
+                                                 makeCharVec(ring_name).data());
+}
+
+wifi_error WifiLegacyHal::registerErrorAlertCallbackHandler(
+    const std::string& iface_name,
+    const on_error_alert_callback& on_user_alert_callback) {
+    if (on_error_alert_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_error_alert_internal_callback = [on_user_alert_callback](
+                                           wifi_request_id id, char* buffer,
+                                           int buffer_size, int err_code) {
+        if (buffer) {
+            CHECK(id == 0);
+            on_user_alert_callback(
+                err_code,
+                std::vector<uint8_t>(
+                    reinterpret_cast<uint8_t*>(buffer),
+                    reinterpret_cast<uint8_t*>(buffer) + buffer_size));
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_alert_handler(
+        0, getIfaceHandle(iface_name), {onAsyncErrorAlert});
+    if (status != WIFI_SUCCESS) {
+        on_error_alert_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::deregisterErrorAlertCallbackHandler(
+    const std::string& iface_name) {
+    if (!on_error_alert_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_error_alert_internal_callback = nullptr;
+    return global_func_table_.wifi_reset_alert_handler(
+        0, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::registerRadioModeChangeCallbackHandler(
+    const std::string& iface_name,
+    const on_radio_mode_change_callback& on_user_change_callback) {
+    if (on_radio_mode_change_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    on_radio_mode_change_internal_callback = [on_user_change_callback](
+                                                 wifi_request_id /* id */,
+                                                 uint32_t num_macs,
+                                                 wifi_mac_info* mac_infos_arr) {
+        if (num_macs > 0 && mac_infos_arr) {
+            std::vector<WifiMacInfo> mac_infos_vec;
+            for (uint32_t i = 0; i < num_macs; i++) {
+                WifiMacInfo mac_info;
+                mac_info.wlan_mac_id = mac_infos_arr[i].wlan_mac_id;
+                mac_info.mac_band = mac_infos_arr[i].mac_band;
+                for (int32_t j = 0; j < mac_infos_arr[i].num_iface; j++) {
+                    WifiIfaceInfo iface_info;
+                    iface_info.name = mac_infos_arr[i].iface_info[j].iface_name;
+                    iface_info.channel = mac_infos_arr[i].iface_info[j].channel;
+                    mac_info.iface_infos.push_back(iface_info);
+                }
+                mac_infos_vec.push_back(mac_info);
+            }
+            on_user_change_callback(mac_infos_vec);
+        }
+    };
+    wifi_error status = global_func_table_.wifi_set_radio_mode_change_handler(
+        0, getIfaceHandle(iface_name), {onAsyncRadioModeChange});
+    if (status != WIFI_SUCCESS) {
+        on_radio_mode_change_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::startRttRangeRequest(
+    const std::string& iface_name, wifi_request_id id,
+    const std::vector<wifi_rtt_config>& rtt_configs,
+    const on_rtt_results_callback& on_results_user_callback) {
+    if (on_rtt_results_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+
+    on_rtt_results_internal_callback =
+        [on_results_user_callback](wifi_request_id id, unsigned num_results,
+                                   wifi_rtt_result* rtt_results[]) {
+            if (num_results > 0 && !rtt_results) {
+                LOG(ERROR) << "Unexpected nullptr in RTT results";
+                return;
+            }
+            std::vector<const wifi_rtt_result*> rtt_results_vec;
+            std::copy_if(rtt_results, rtt_results + num_results,
+                         back_inserter(rtt_results_vec),
+                         [](wifi_rtt_result* rtt_result) {
+                             return rtt_result != nullptr;
+                         });
+            on_results_user_callback(id, rtt_results_vec);
+        };
+
+    std::vector<wifi_rtt_config> rtt_configs_internal(rtt_configs);
+    wifi_error status = global_func_table_.wifi_rtt_range_request(
+        id, getIfaceHandle(iface_name), rtt_configs.size(),
+        rtt_configs_internal.data(), {onAsyncRttResults});
+    if (status != WIFI_SUCCESS) {
+        on_rtt_results_internal_callback = nullptr;
+    }
+    return status;
+}
+
+wifi_error WifiLegacyHal::cancelRttRangeRequest(
+    const std::string& iface_name, wifi_request_id id,
+    const std::vector<std::array<uint8_t, 6>>& mac_addrs) {
+    if (!on_rtt_results_internal_callback) {
+        return WIFI_ERROR_NOT_AVAILABLE;
+    }
+    static_assert(sizeof(mac_addr) == sizeof(std::array<uint8_t, 6>),
+                  "MAC address size mismatch");
+    // TODO: How do we handle partial cancels (i.e only a subset of enabled mac
+    // addressed are cancelled).
+    std::vector<std::array<uint8_t, 6>> mac_addrs_internal(mac_addrs);
+    wifi_error status = global_func_table_.wifi_rtt_range_cancel(
+        id, getIfaceHandle(iface_name), mac_addrs.size(),
+        reinterpret_cast<mac_addr*>(mac_addrs_internal.data()));
+    // If the request Id is wrong, don't stop the ongoing range request. Any
+    // other error should be treated as the end of rtt ranging.
+    if (status != WIFI_ERROR_INVALID_REQUEST_ID) {
+        on_rtt_results_internal_callback = nullptr;
+    }
+    return status;
+}
+
+std::pair<wifi_error, wifi_rtt_capabilities> WifiLegacyHal::getRttCapabilities(
+    const std::string& iface_name) {
+    wifi_rtt_capabilities rtt_caps;
+    wifi_error status = global_func_table_.wifi_get_rtt_capabilities(
+        getIfaceHandle(iface_name), &rtt_caps);
+    return {status, rtt_caps};
+}
+
+std::pair<wifi_error, wifi_rtt_responder> WifiLegacyHal::getRttResponderInfo(
+    const std::string& iface_name) {
+    wifi_rtt_responder rtt_responder;
+    wifi_error status = global_func_table_.wifi_rtt_get_responder_info(
+        getIfaceHandle(iface_name), &rtt_responder);
+    return {status, rtt_responder};
+}
+
+wifi_error WifiLegacyHal::enableRttResponder(
+    const std::string& iface_name, wifi_request_id id,
+    const wifi_channel_info& channel_hint, uint32_t max_duration_secs,
+    const wifi_rtt_responder& info) {
+    wifi_rtt_responder info_internal(info);
+    return global_func_table_.wifi_enable_responder(
+        id, getIfaceHandle(iface_name), channel_hint, max_duration_secs,
+        &info_internal);
+}
+
+wifi_error WifiLegacyHal::disableRttResponder(const std::string& iface_name,
+                                              wifi_request_id id) {
+    return global_func_table_.wifi_disable_responder(
+        id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::setRttLci(const std::string& iface_name,
+                                    wifi_request_id id,
+                                    const wifi_lci_information& info) {
+    wifi_lci_information info_internal(info);
+    return global_func_table_.wifi_set_lci(id, getIfaceHandle(iface_name),
+                                           &info_internal);
+}
+
+wifi_error WifiLegacyHal::setRttLcr(const std::string& iface_name,
+                                    wifi_request_id id,
+                                    const wifi_lcr_information& info) {
+    wifi_lcr_information info_internal(info);
+    return global_func_table_.wifi_set_lcr(id, getIfaceHandle(iface_name),
+                                           &info_internal);
+}
+
+wifi_error WifiLegacyHal::nanRegisterCallbackHandlers(
+    const std::string& iface_name, const NanCallbackHandlers& user_callbacks) {
+    on_nan_notify_response_user_callback = user_callbacks.on_notify_response;
+    on_nan_event_publish_terminated_user_callback =
+        user_callbacks.on_event_publish_terminated;
+    on_nan_event_match_user_callback = user_callbacks.on_event_match;
+    on_nan_event_match_expired_user_callback =
+        user_callbacks.on_event_match_expired;
+    on_nan_event_subscribe_terminated_user_callback =
+        user_callbacks.on_event_subscribe_terminated;
+    on_nan_event_followup_user_callback = user_callbacks.on_event_followup;
+    on_nan_event_disc_eng_event_user_callback =
+        user_callbacks.on_event_disc_eng_event;
+    on_nan_event_disabled_user_callback = user_callbacks.on_event_disabled;
+    on_nan_event_tca_user_callback = user_callbacks.on_event_tca;
+    on_nan_event_beacon_sdf_payload_user_callback =
+        user_callbacks.on_event_beacon_sdf_payload;
+    on_nan_event_data_path_request_user_callback =
+        user_callbacks.on_event_data_path_request;
+    on_nan_event_data_path_confirm_user_callback =
+        user_callbacks.on_event_data_path_confirm;
+    on_nan_event_data_path_end_user_callback =
+        user_callbacks.on_event_data_path_end;
+    on_nan_event_transmit_follow_up_user_callback =
+        user_callbacks.on_event_transmit_follow_up;
+    on_nan_event_range_request_user_callback =
+        user_callbacks.on_event_range_request;
+    on_nan_event_range_report_user_callback =
+        user_callbacks.on_event_range_report;
+    on_nan_event_schedule_update_user_callback =
+        user_callbacks.on_event_schedule_update;
+
+    return global_func_table_.wifi_nan_register_handler(
+        getIfaceHandle(iface_name),
+        {onAysncNanNotifyResponse, onAysncNanEventPublishReplied,
+         onAysncNanEventPublishTerminated, onAysncNanEventMatch,
+         onAysncNanEventMatchExpired, onAysncNanEventSubscribeTerminated,
+         onAysncNanEventFollowup, onAysncNanEventDiscEngEvent,
+         onAysncNanEventDisabled, onAysncNanEventTca,
+         onAysncNanEventBeaconSdfPayload, onAysncNanEventDataPathRequest,
+         onAysncNanEventDataPathConfirm, onAysncNanEventDataPathEnd,
+         onAysncNanEventTransmitFollowUp, onAysncNanEventRangeRequest,
+         onAysncNanEventRangeReport, onAsyncNanEventScheduleUpdate});
+}
+
+wifi_error WifiLegacyHal::nanEnableRequest(const std::string& iface_name,
+                                           transaction_id id,
+                                           const NanEnableRequest& msg) {
+    NanEnableRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_enable_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDisableRequest(const std::string& iface_name,
+                                            transaction_id id) {
+    return global_func_table_.wifi_nan_disable_request(
+        id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanPublishRequest(const std::string& iface_name,
+                                            transaction_id id,
+                                            const NanPublishRequest& msg) {
+    NanPublishRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_publish_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanPublishCancelRequest(
+    const std::string& iface_name, transaction_id id,
+    const NanPublishCancelRequest& msg) {
+    NanPublishCancelRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_publish_cancel_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeRequest(const std::string& iface_name,
+                                              transaction_id id,
+                                              const NanSubscribeRequest& msg) {
+    NanSubscribeRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_subscribe_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanSubscribeCancelRequest(
+    const std::string& iface_name, transaction_id id,
+    const NanSubscribeCancelRequest& msg) {
+    NanSubscribeCancelRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_subscribe_cancel_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTransmitFollowupRequest(
+    const std::string& iface_name, transaction_id id,
+    const NanTransmitFollowupRequest& msg) {
+    NanTransmitFollowupRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_transmit_followup_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanStatsRequest(const std::string& iface_name,
+                                          transaction_id id,
+                                          const NanStatsRequest& msg) {
+    NanStatsRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_stats_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanConfigRequest(const std::string& iface_name,
+                                           transaction_id id,
+                                           const NanConfigRequest& msg) {
+    NanConfigRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_config_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanTcaRequest(const std::string& iface_name,
+                                        transaction_id id,
+                                        const NanTCARequest& msg) {
+    NanTCARequest msg_internal(msg);
+    return global_func_table_.wifi_nan_tca_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanBeaconSdfPayloadRequest(
+    const std::string& iface_name, transaction_id id,
+    const NanBeaconSdfPayloadRequest& msg) {
+    NanBeaconSdfPayloadRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_beacon_sdf_payload_request(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+std::pair<wifi_error, NanVersion> WifiLegacyHal::nanGetVersion() {
+    NanVersion version;
+    wifi_error status =
+        global_func_table_.wifi_nan_get_version(global_handle_, &version);
+    return {status, version};
+}
+
+wifi_error WifiLegacyHal::nanGetCapabilities(const std::string& iface_name,
+                                             transaction_id id) {
+    return global_func_table_.wifi_nan_get_capabilities(
+        id, getIfaceHandle(iface_name));
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceCreate(
+    const std::string& iface_name, transaction_id id,
+    const std::string& data_iface_name) {
+    return global_func_table_.wifi_nan_data_interface_create(
+        id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataInterfaceDelete(
+    const std::string& iface_name, transaction_id id,
+    const std::string& data_iface_name) {
+    return global_func_table_.wifi_nan_data_interface_delete(
+        id, getIfaceHandle(iface_name), makeCharVec(data_iface_name).data());
+}
+
+wifi_error WifiLegacyHal::nanDataRequestInitiator(
+    const std::string& iface_name, transaction_id id,
+    const NanDataPathInitiatorRequest& msg) {
+    NanDataPathInitiatorRequest msg_internal(msg);
+    return global_func_table_.wifi_nan_data_request_initiator(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+wifi_error WifiLegacyHal::nanDataIndicationResponse(
+    const std::string& iface_name, transaction_id id,
+    const NanDataPathIndicationResponse& msg) {
+    NanDataPathIndicationResponse msg_internal(msg);
+    return global_func_table_.wifi_nan_data_indication_response(
+        id, getIfaceHandle(iface_name), &msg_internal);
+}
+
+typedef struct {
+    u8 num_ndp_instances;
+    NanDataPathId ndp_instance_id;
+} NanDataPathEndSingleNdpIdRequest;
+
+wifi_error WifiLegacyHal::nanDataEnd(const std::string& iface_name,
+                                     transaction_id id,
+                                     uint32_t ndpInstanceId) {
+    NanDataPathEndSingleNdpIdRequest msg;
+    msg.num_ndp_instances = 1;
+    msg.ndp_instance_id = ndpInstanceId;
+    wifi_error status = global_func_table_.wifi_nan_data_end(
+        id, getIfaceHandle(iface_name), (NanDataPathEndRequest*)&msg);
+    return status;
+}
+
+wifi_error WifiLegacyHal::setCountryCode(const std::string& iface_name,
+                                         std::array<int8_t, 2> code) {
+    std::string code_str(code.data(), code.data() + code.size());
+    return global_func_table_.wifi_set_country_code(getIfaceHandle(iface_name),
+                                                    code_str.c_str());
+}
+
+wifi_error WifiLegacyHal::retrieveIfaceHandles() {
+    wifi_interface_handle* iface_handles = nullptr;
+    int num_iface_handles = 0;
+    wifi_error status = global_func_table_.wifi_get_ifaces(
+        global_handle_, &num_iface_handles, &iface_handles);
+    if (status != WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to enumerate interface handles";
+        return status;
+    }
+    for (int i = 0; i < num_iface_handles; ++i) {
+        std::array<char, IFNAMSIZ> iface_name_arr = {};
+        status = global_func_table_.wifi_get_iface_name(
+            iface_handles[i], iface_name_arr.data(), iface_name_arr.size());
+        if (status != WIFI_SUCCESS) {
+            LOG(WARNING) << "Failed to get interface handle name";
+            continue;
+        }
+        // Assuming the interface name is null terminated since the legacy HAL
+        // API does not return a size.
+        std::string iface_name(iface_name_arr.data());
+        LOG(INFO) << "Adding interface handle for " << iface_name;
+        iface_name_to_handle_[iface_name] = iface_handles[i];
+    }
+    return WIFI_SUCCESS;
+}
+
+wifi_interface_handle WifiLegacyHal::getIfaceHandle(
+    const std::string& iface_name) {
+    const auto iface_handle_iter = iface_name_to_handle_.find(iface_name);
+    if (iface_handle_iter == iface_name_to_handle_.end()) {
+        LOG(ERROR) << "Unknown iface name: " << iface_name;
+        return nullptr;
+    }
+    return iface_handle_iter->second;
+}
+
+void WifiLegacyHal::runEventLoop() {
+    LOG(DEBUG) << "Starting legacy HAL event loop";
+    global_func_table_.wifi_event_loop(global_handle_);
+    const auto lock = hidl_sync_util::acquireGlobalLock();
+    if (!awaiting_event_loop_termination_) {
+        LOG(FATAL)
+            << "Legacy HAL event loop terminated, but HAL was not stopping";
+    }
+    LOG(DEBUG) << "Legacy HAL event loop terminated";
+    awaiting_event_loop_termination_ = false;
+    stop_wait_cv_.notify_one();
+}
+
+std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
+WifiLegacyHal::getGscanCachedResults(const std::string& iface_name) {
+    std::vector<wifi_cached_scan_results> cached_scan_results;
+    cached_scan_results.resize(kMaxCachedGscanResults);
+    int32_t num_results = 0;
+    wifi_error status = global_func_table_.wifi_get_cached_gscan_results(
+        getIfaceHandle(iface_name), true /* always flush */,
+        cached_scan_results.size(), cached_scan_results.data(), &num_results);
+    CHECK(num_results >= 0 &&
+          static_cast<uint32_t>(num_results) <= kMaxCachedGscanResults);
+    cached_scan_results.resize(num_results);
+    // Check for invalid IE lengths in these cached scan results and correct it.
+    for (auto& cached_scan_result : cached_scan_results) {
+        int num_scan_results = cached_scan_result.num_results;
+        for (int i = 0; i < num_scan_results; i++) {
+            auto& scan_result = cached_scan_result.results[i];
+            if (scan_result.ie_length > 0) {
+                LOG(DEBUG) << "Cached scan result has non-zero IE length "
+                           << scan_result.ie_length;
+                scan_result.ie_length = 0;
+            }
+        }
+    }
+    return {status, std::move(cached_scan_results)};
+}
+
+void WifiLegacyHal::invalidate() {
+    global_handle_ = nullptr;
+    iface_name_to_handle_.clear();
+    on_driver_memory_dump_internal_callback = nullptr;
+    on_firmware_memory_dump_internal_callback = nullptr;
+    on_gscan_event_internal_callback = nullptr;
+    on_gscan_full_result_internal_callback = nullptr;
+    on_link_layer_stats_result_internal_callback = nullptr;
+    on_rssi_threshold_breached_internal_callback = nullptr;
+    on_ring_buffer_data_internal_callback = nullptr;
+    on_error_alert_internal_callback = nullptr;
+    on_radio_mode_change_internal_callback = nullptr;
+    on_rtt_results_internal_callback = nullptr;
+    on_nan_notify_response_user_callback = nullptr;
+    on_nan_event_publish_terminated_user_callback = nullptr;
+    on_nan_event_match_user_callback = nullptr;
+    on_nan_event_match_expired_user_callback = nullptr;
+    on_nan_event_subscribe_terminated_user_callback = nullptr;
+    on_nan_event_followup_user_callback = nullptr;
+    on_nan_event_disc_eng_event_user_callback = nullptr;
+    on_nan_event_disabled_user_callback = nullptr;
+    on_nan_event_tca_user_callback = nullptr;
+    on_nan_event_beacon_sdf_payload_user_callback = nullptr;
+    on_nan_event_data_path_request_user_callback = nullptr;
+    on_nan_event_data_path_confirm_user_callback = nullptr;
+    on_nan_event_data_path_end_user_callback = nullptr;
+    on_nan_event_transmit_follow_up_user_callback = nullptr;
+    on_nan_event_range_request_user_callback = nullptr;
+    on_nan_event_range_report_user_callback = nullptr;
+    on_nan_event_schedule_update_user_callback = nullptr;
+}
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_legacy_hal.h b/wifi/1.2/default/wifi_legacy_hal.h
new file mode 100644
index 0000000..bd68bcd
--- /dev/null
+++ b/wifi/1.2/default/wifi_legacy_hal.h
@@ -0,0 +1,389 @@
+/*
+ * 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 WIFI_LEGACY_HAL_H_
+#define WIFI_LEGACY_HAL_H_
+
+#include <condition_variable>
+#include <functional>
+#include <map>
+#include <thread>
+#include <vector>
+
+#include <wifi_system/interface_tool.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+// This is in a separate namespace to prevent typename conflicts between
+// the legacy HAL types and the HIDL interface types.
+namespace legacy_hal {
+// Wrap all the types defined inside the legacy HAL header files inside this
+// namespace.
+#include <hardware_legacy/wifi_hal.h>
+
+// APF capabilities supported by the iface.
+struct PacketFilterCapabilities {
+    uint32_t version;
+    uint32_t max_len;
+};
+
+// WARNING: We don't care about the variable sized members of either
+// |wifi_iface_stat|, |wifi_radio_stat| structures. So, using the pragma
+// to escape the compiler warnings regarding this.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
+// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
+// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
+// into a separate return element to avoid passing pointers around.
+struct LinkLayerRadioStats {
+    wifi_radio_stat stats;
+    std::vector<uint32_t> tx_time_per_levels;
+};
+
+struct LinkLayerStats {
+    wifi_iface_stat iface;
+    std::vector<LinkLayerRadioStats> radios;
+};
+#pragma GCC diagnostic pop
+
+// The |WLAN_DRIVER_WAKE_REASON_CNT.cmd_event_wake_cnt| and
+// |WLAN_DRIVER_WAKE_REASON_CNT.driver_fw_local_wake_cnt| stats is provided
+// as a pointer in |WLAN_DRIVER_WAKE_REASON_CNT| structure in the legacy HAL
+// API. Separate that out into a separate return elements to avoid passing
+// pointers around.
+struct WakeReasonStats {
+    WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
+    std::vector<uint32_t> cmd_event_wake_cnt;
+    std::vector<uint32_t> driver_fw_local_wake_cnt;
+};
+
+// NAN response and event callbacks struct.
+struct NanCallbackHandlers {
+    // NotifyResponse invoked to notify the status of the Request.
+    std::function<void(transaction_id, const NanResponseMsg&)>
+        on_notify_response;
+    // Various event callbacks.
+    std::function<void(const NanPublishTerminatedInd&)>
+        on_event_publish_terminated;
+    std::function<void(const NanMatchInd&)> on_event_match;
+    std::function<void(const NanMatchExpiredInd&)> on_event_match_expired;
+    std::function<void(const NanSubscribeTerminatedInd&)>
+        on_event_subscribe_terminated;
+    std::function<void(const NanFollowupInd&)> on_event_followup;
+    std::function<void(const NanDiscEngEventInd&)> on_event_disc_eng_event;
+    std::function<void(const NanDisabledInd&)> on_event_disabled;
+    std::function<void(const NanTCAInd&)> on_event_tca;
+    std::function<void(const NanBeaconSdfPayloadInd&)>
+        on_event_beacon_sdf_payload;
+    std::function<void(const NanDataPathRequestInd&)>
+        on_event_data_path_request;
+    std::function<void(const NanDataPathConfirmInd&)>
+        on_event_data_path_confirm;
+    std::function<void(const NanDataPathEndInd&)> on_event_data_path_end;
+    std::function<void(const NanTransmitFollowupInd&)>
+        on_event_transmit_follow_up;
+    std::function<void(const NanRangeRequestInd&)> on_event_range_request;
+    std::function<void(const NanRangeReportInd&)> on_event_range_report;
+    std::function<void(const NanDataPathScheduleUpdateInd&)> on_event_schedule_update;
+};
+
+// Full scan results contain IE info and are hence passed by reference, to
+// preserve the variable length array member |ie_data|. Callee must not retain
+// the pointer.
+using on_gscan_full_result_callback =
+    std::function<void(wifi_request_id, const wifi_scan_result*, uint32_t)>;
+// These scan results don't contain any IE info, so no need to pass by
+// reference.
+using on_gscan_results_callback = std::function<void(
+    wifi_request_id, const std::vector<wifi_cached_scan_results>&)>;
+
+// Invoked when the rssi value breaches the thresholds set.
+using on_rssi_threshold_breached_callback =
+    std::function<void(wifi_request_id, std::array<uint8_t, 6>, int8_t)>;
+
+// Callback for RTT range request results.
+// Rtt results contain IE info and are hence passed by reference, to
+// preserve the |LCI| and |LCR| pointers. Callee must not retain
+// the pointer.
+using on_rtt_results_callback = std::function<void(
+    wifi_request_id, const std::vector<const wifi_rtt_result*>&)>;
+
+// Callback for ring buffer data.
+using on_ring_buffer_data_callback =
+    std::function<void(const std::string&, const std::vector<uint8_t>&,
+                       const wifi_ring_buffer_status&)>;
+
+// Callback for alerts.
+using on_error_alert_callback =
+    std::function<void(int32_t, const std::vector<uint8_t>&)>;
+
+// Struct for the mac info from the legacy HAL. This is a cleaner version
+// of the |wifi_mac_info| & |wifi_iface_info|.
+typedef struct {
+    std::string name;
+    wifi_channel channel;
+} WifiIfaceInfo;
+
+typedef struct {
+    uint32_t wlan_mac_id;
+    /* BIT MASK of BIT(WLAN_MAC*) as represented by wlan_mac_band */
+    uint32_t mac_band;
+    /* Represents the connected Wi-Fi interfaces associated with each MAC */
+    std::vector<WifiIfaceInfo> iface_infos;
+} WifiMacInfo;
+
+// Callback for radio mode change
+using on_radio_mode_change_callback =
+    std::function<void(const std::vector<WifiMacInfo>&)>;
+
+/**
+ * Class that encapsulates all legacy HAL interactions.
+ * This class manages the lifetime of the event loop thread used by legacy HAL.
+ *
+ * Note: aThere will only be a single instance of this class created in the Wifi
+ * object and will be valid for the lifetime of the process.
+ */
+class WifiLegacyHal {
+   public:
+    WifiLegacyHal();
+    virtual ~WifiLegacyHal() = default;
+
+    // Initialize the legacy HAL function table.
+    virtual wifi_error initialize();
+    // Start the legacy HAL and the event looper thread.
+    virtual wifi_error start();
+    // Deinitialize the legacy HAL and wait for the event loop thread to exit
+    // using a predefined timeout.
+    virtual wifi_error stop(std::unique_lock<std::recursive_mutex>* lock,
+                            const std::function<void()>& on_complete_callback);
+    // Wrappers for all the functions in the legacy HAL function table.
+    std::pair<wifi_error, std::string> getDriverVersion(
+        const std::string& iface_name);
+    std::pair<wifi_error, std::string> getFirmwareVersion(
+        const std::string& iface_name);
+    std::pair<wifi_error, std::vector<uint8_t>> requestDriverMemoryDump(
+        const std::string& iface_name);
+    std::pair<wifi_error, std::vector<uint8_t>> requestFirmwareMemoryDump(
+        const std::string& iface_name);
+    std::pair<wifi_error, uint32_t> getSupportedFeatureSet(
+        const std::string& iface_name);
+    // APF functions.
+    std::pair<wifi_error, PacketFilterCapabilities> getPacketFilterCapabilities(
+        const std::string& iface_name);
+    wifi_error setPacketFilter(const std::string& iface_name,
+                               const std::vector<uint8_t>& program);
+    // Gscan functions.
+    std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
+        const std::string& iface_name);
+    // These API's provides a simplified interface over the legacy Gscan API's:
+    // a) All scan events from the legacy HAL API other than the
+    //    |WIFI_SCAN_FAILED| are treated as notification of results.
+    //    This method then retrieves the cached scan results from the legacy
+    //    HAL API and triggers the externally provided
+    //    |on_results_user_callback| on success.
+    // b) |WIFI_SCAN_FAILED| scan event or failure to retrieve cached scan
+    // results
+    //    triggers the externally provided |on_failure_user_callback|.
+    // c) Full scan result event triggers the externally provided
+    //    |on_full_result_user_callback|.
+    wifi_error startGscan(
+        const std::string& iface_name, wifi_request_id id,
+        const wifi_scan_cmd_params& params,
+        const std::function<void(wifi_request_id)>& on_failure_callback,
+        const on_gscan_results_callback& on_results_callback,
+        const on_gscan_full_result_callback& on_full_result_callback);
+    wifi_error stopGscan(const std::string& iface_name, wifi_request_id id);
+    std::pair<wifi_error, std::vector<uint32_t>> getValidFrequenciesForBand(
+        const std::string& iface_name, wifi_band band);
+    virtual wifi_error setDfsFlag(const std::string& iface_name, bool dfs_on);
+    // Link layer stats functions.
+    wifi_error enableLinkLayerStats(const std::string& iface_name, bool debug);
+    wifi_error disableLinkLayerStats(const std::string& iface_name);
+    std::pair<wifi_error, LinkLayerStats> getLinkLayerStats(
+        const std::string& iface_name);
+    // RSSI monitor functions.
+    wifi_error startRssiMonitoring(const std::string& iface_name,
+                                   wifi_request_id id, int8_t max_rssi,
+                                   int8_t min_rssi,
+                                   const on_rssi_threshold_breached_callback&
+                                       on_threshold_breached_callback);
+    wifi_error stopRssiMonitoring(const std::string& iface_name,
+                                  wifi_request_id id);
+    std::pair<wifi_error, wifi_roaming_capabilities> getRoamingCapabilities(
+        const std::string& iface_name);
+    wifi_error configureRoaming(const std::string& iface_name,
+                                const wifi_roaming_config& config);
+    wifi_error enableFirmwareRoaming(const std::string& iface_name,
+                                     fw_roaming_state_t state);
+    wifi_error configureNdOffload(const std::string& iface_name, bool enable);
+    wifi_error startSendingOffloadedPacket(
+        const std::string& iface_name, uint32_t cmd_id,
+        const std::vector<uint8_t>& ip_packet_data,
+        const std::array<uint8_t, 6>& src_address,
+        const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
+    wifi_error stopSendingOffloadedPacket(const std::string& iface_name,
+                                          uint32_t cmd_id);
+    wifi_error setScanningMacOui(const std::string& iface_name,
+                                 const std::array<uint8_t, 3>& oui);
+    wifi_error selectTxPowerScenario(const std::string& iface_name,
+                                     wifi_power_scenario scenario);
+    wifi_error resetTxPowerScenario(const std::string& iface_name);
+    // Logger/debug functions.
+    std::pair<wifi_error, uint32_t> getLoggerSupportedFeatureSet(
+        const std::string& iface_name);
+    wifi_error startPktFateMonitoring(const std::string& iface_name);
+    std::pair<wifi_error, std::vector<wifi_tx_report>> getTxPktFates(
+        const std::string& iface_name);
+    std::pair<wifi_error, std::vector<wifi_rx_report>> getRxPktFates(
+        const std::string& iface_name);
+    std::pair<wifi_error, WakeReasonStats> getWakeReasonStats(
+        const std::string& iface_name);
+    wifi_error registerRingBufferCallbackHandler(
+        const std::string& iface_name,
+        const on_ring_buffer_data_callback& on_data_callback);
+    wifi_error deregisterRingBufferCallbackHandler(
+        const std::string& iface_name);
+    std::pair<wifi_error, std::vector<wifi_ring_buffer_status>>
+    getRingBuffersStatus(const std::string& iface_name);
+    wifi_error startRingBufferLogging(const std::string& iface_name,
+                                      const std::string& ring_name,
+                                      uint32_t verbose_level,
+                                      uint32_t max_interval_sec,
+                                      uint32_t min_data_size);
+    wifi_error getRingBufferData(const std::string& iface_name,
+                                 const std::string& ring_name);
+    wifi_error registerErrorAlertCallbackHandler(
+        const std::string& iface_name,
+        const on_error_alert_callback& on_alert_callback);
+    wifi_error deregisterErrorAlertCallbackHandler(
+        const std::string& iface_name);
+    // Radio mode functions.
+    wifi_error registerRadioModeChangeCallbackHandler(
+        const std::string& iface_name,
+        const on_radio_mode_change_callback& on_user_change_callback);
+    // RTT functions.
+    wifi_error startRttRangeRequest(
+        const std::string& iface_name, wifi_request_id id,
+        const std::vector<wifi_rtt_config>& rtt_configs,
+        const on_rtt_results_callback& on_results_callback);
+    wifi_error cancelRttRangeRequest(
+        const std::string& iface_name, wifi_request_id id,
+        const std::vector<std::array<uint8_t, 6>>& mac_addrs);
+    std::pair<wifi_error, wifi_rtt_capabilities> getRttCapabilities(
+        const std::string& iface_name);
+    std::pair<wifi_error, wifi_rtt_responder> getRttResponderInfo(
+        const std::string& iface_name);
+    wifi_error enableRttResponder(const std::string& iface_name,
+                                  wifi_request_id id,
+                                  const wifi_channel_info& channel_hint,
+                                  uint32_t max_duration_secs,
+                                  const wifi_rtt_responder& info);
+    wifi_error disableRttResponder(const std::string& iface_name,
+                                   wifi_request_id id);
+    wifi_error setRttLci(const std::string& iface_name, wifi_request_id id,
+                         const wifi_lci_information& info);
+    wifi_error setRttLcr(const std::string& iface_name, wifi_request_id id,
+                         const wifi_lcr_information& info);
+    // NAN functions.
+    virtual wifi_error nanRegisterCallbackHandlers(
+        const std::string& iface_name, const NanCallbackHandlers& callbacks);
+    wifi_error nanEnableRequest(const std::string& iface_name,
+                                transaction_id id, const NanEnableRequest& msg);
+    virtual wifi_error nanDisableRequest(const std::string& iface_name,
+                                         transaction_id id);
+    wifi_error nanPublishRequest(const std::string& iface_name,
+                                 transaction_id id,
+                                 const NanPublishRequest& msg);
+    wifi_error nanPublishCancelRequest(const std::string& iface_name,
+                                       transaction_id id,
+                                       const NanPublishCancelRequest& msg);
+    wifi_error nanSubscribeRequest(const std::string& iface_name,
+                                   transaction_id id,
+                                   const NanSubscribeRequest& msg);
+    wifi_error nanSubscribeCancelRequest(const std::string& iface_name,
+                                         transaction_id id,
+                                         const NanSubscribeCancelRequest& msg);
+    wifi_error nanTransmitFollowupRequest(
+        const std::string& iface_name, transaction_id id,
+        const NanTransmitFollowupRequest& msg);
+    wifi_error nanStatsRequest(const std::string& iface_name, transaction_id id,
+                               const NanStatsRequest& msg);
+    wifi_error nanConfigRequest(const std::string& iface_name,
+                                transaction_id id, const NanConfigRequest& msg);
+    wifi_error nanTcaRequest(const std::string& iface_name, transaction_id id,
+                             const NanTCARequest& msg);
+    wifi_error nanBeaconSdfPayloadRequest(
+        const std::string& iface_name, transaction_id id,
+        const NanBeaconSdfPayloadRequest& msg);
+    std::pair<wifi_error, NanVersion> nanGetVersion();
+    wifi_error nanGetCapabilities(const std::string& iface_name,
+                                  transaction_id id);
+    wifi_error nanDataInterfaceCreate(const std::string& iface_name,
+                                      transaction_id id,
+                                      const std::string& data_iface_name);
+    virtual wifi_error nanDataInterfaceDelete(
+        const std::string& iface_name, transaction_id id,
+        const std::string& data_iface_name);
+    wifi_error nanDataRequestInitiator(const std::string& iface_name,
+                                       transaction_id id,
+                                       const NanDataPathInitiatorRequest& msg);
+    wifi_error nanDataIndicationResponse(
+        const std::string& iface_name, transaction_id id,
+        const NanDataPathIndicationResponse& msg);
+    wifi_error nanDataEnd(const std::string& iface_name, transaction_id id,
+                          uint32_t ndpInstanceId);
+    // AP functions.
+    wifi_error setCountryCode(const std::string& iface_name,
+                              std::array<int8_t, 2> code);
+
+   private:
+    // Retrieve interface handles for all the available interfaces.
+    wifi_error retrieveIfaceHandles();
+    wifi_interface_handle getIfaceHandle(const std::string& iface_name);
+    // Run the legacy HAL event loop thread.
+    void runEventLoop();
+    // Retrieve the cached gscan results to pass the results back to the
+    // external callbacks.
+    std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
+    getGscanCachedResults(const std::string& iface_name);
+    void invalidate();
+
+    // Global function table of legacy HAL.
+    wifi_hal_fn global_func_table_;
+    // Opaque handle to be used for all global operations.
+    wifi_handle global_handle_;
+    // Map of interface name to handle that is to be used for all interface
+    // specific operations.
+    std::map<std::string, wifi_interface_handle> iface_name_to_handle_;
+    // Flag to indicate if we have initiated the cleanup of legacy HAL.
+    std::atomic<bool> awaiting_event_loop_termination_;
+    std::condition_variable_any stop_wait_cv_;
+    // Flag to indicate if the legacy HAL has been started.
+    bool is_started_;
+    wifi_system::InterfaceTool iface_tool_;
+};
+
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_LEGACY_HAL_H_
diff --git a/wifi/1.2/default/wifi_legacy_hal_stubs.cpp b/wifi/1.2/default/wifi_legacy_hal_stubs.cpp
new file mode 100644
index 0000000..2ee2aa2
--- /dev/null
+++ b/wifi/1.2/default/wifi_legacy_hal_stubs.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#include "wifi_legacy_hal_stubs.h"
+
+// TODO: Remove these stubs from HalTool in libwifi-system.
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace legacy_hal {
+template <typename>
+struct stubFunction;
+
+template <typename R, typename... Args>
+struct stubFunction<R (*)(Args...)> {
+    static constexpr R invoke(Args...) { return WIFI_ERROR_NOT_SUPPORTED; }
+};
+template <typename... Args>
+struct stubFunction<void (*)(Args...)> {
+    static constexpr void invoke(Args...) {}
+};
+
+template <typename T>
+void populateStubFor(T* val) {
+    *val = &stubFunction<T>::invoke;
+}
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn) {
+    if (hal_fn == nullptr) {
+        return false;
+    }
+    populateStubFor(&hal_fn->wifi_initialize);
+    populateStubFor(&hal_fn->wifi_cleanup);
+    populateStubFor(&hal_fn->wifi_event_loop);
+    populateStubFor(&hal_fn->wifi_get_error_info);
+    populateStubFor(&hal_fn->wifi_get_supported_feature_set);
+    populateStubFor(&hal_fn->wifi_get_concurrency_matrix);
+    populateStubFor(&hal_fn->wifi_set_scanning_mac_oui);
+    populateStubFor(&hal_fn->wifi_get_supported_channels);
+    populateStubFor(&hal_fn->wifi_is_epr_supported);
+    populateStubFor(&hal_fn->wifi_get_ifaces);
+    populateStubFor(&hal_fn->wifi_get_iface_name);
+    populateStubFor(&hal_fn->wifi_set_iface_event_handler);
+    populateStubFor(&hal_fn->wifi_reset_iface_event_handler);
+    populateStubFor(&hal_fn->wifi_start_gscan);
+    populateStubFor(&hal_fn->wifi_stop_gscan);
+    populateStubFor(&hal_fn->wifi_get_cached_gscan_results);
+    populateStubFor(&hal_fn->wifi_set_bssid_hotlist);
+    populateStubFor(&hal_fn->wifi_reset_bssid_hotlist);
+    populateStubFor(&hal_fn->wifi_set_significant_change_handler);
+    populateStubFor(&hal_fn->wifi_reset_significant_change_handler);
+    populateStubFor(&hal_fn->wifi_get_gscan_capabilities);
+    populateStubFor(&hal_fn->wifi_set_link_stats);
+    populateStubFor(&hal_fn->wifi_get_link_stats);
+    populateStubFor(&hal_fn->wifi_clear_link_stats);
+    populateStubFor(&hal_fn->wifi_get_valid_channels);
+    populateStubFor(&hal_fn->wifi_rtt_range_request);
+    populateStubFor(&hal_fn->wifi_rtt_range_cancel);
+    populateStubFor(&hal_fn->wifi_get_rtt_capabilities);
+    populateStubFor(&hal_fn->wifi_rtt_get_responder_info);
+    populateStubFor(&hal_fn->wifi_enable_responder);
+    populateStubFor(&hal_fn->wifi_disable_responder);
+    populateStubFor(&hal_fn->wifi_set_nodfs_flag);
+    populateStubFor(&hal_fn->wifi_start_logging);
+    populateStubFor(&hal_fn->wifi_set_epno_list);
+    populateStubFor(&hal_fn->wifi_reset_epno_list);
+    populateStubFor(&hal_fn->wifi_set_country_code);
+    populateStubFor(&hal_fn->wifi_get_firmware_memory_dump);
+    populateStubFor(&hal_fn->wifi_set_log_handler);
+    populateStubFor(&hal_fn->wifi_reset_log_handler);
+    populateStubFor(&hal_fn->wifi_set_alert_handler);
+    populateStubFor(&hal_fn->wifi_reset_alert_handler);
+    populateStubFor(&hal_fn->wifi_get_firmware_version);
+    populateStubFor(&hal_fn->wifi_get_ring_buffers_status);
+    populateStubFor(&hal_fn->wifi_get_logger_supported_feature_set);
+    populateStubFor(&hal_fn->wifi_get_ring_data);
+    populateStubFor(&hal_fn->wifi_enable_tdls);
+    populateStubFor(&hal_fn->wifi_disable_tdls);
+    populateStubFor(&hal_fn->wifi_get_tdls_status);
+    populateStubFor(&hal_fn->wifi_get_tdls_capabilities);
+    populateStubFor(&hal_fn->wifi_get_driver_version);
+    populateStubFor(&hal_fn->wifi_set_passpoint_list);
+    populateStubFor(&hal_fn->wifi_reset_passpoint_list);
+    populateStubFor(&hal_fn->wifi_set_lci);
+    populateStubFor(&hal_fn->wifi_set_lcr);
+    populateStubFor(&hal_fn->wifi_start_sending_offloaded_packet);
+    populateStubFor(&hal_fn->wifi_stop_sending_offloaded_packet);
+    populateStubFor(&hal_fn->wifi_start_rssi_monitoring);
+    populateStubFor(&hal_fn->wifi_stop_rssi_monitoring);
+    populateStubFor(&hal_fn->wifi_get_wake_reason_stats);
+    populateStubFor(&hal_fn->wifi_configure_nd_offload);
+    populateStubFor(&hal_fn->wifi_get_driver_memory_dump);
+    populateStubFor(&hal_fn->wifi_start_pkt_fate_monitoring);
+    populateStubFor(&hal_fn->wifi_get_tx_pkt_fates);
+    populateStubFor(&hal_fn->wifi_get_rx_pkt_fates);
+    populateStubFor(&hal_fn->wifi_nan_enable_request);
+    populateStubFor(&hal_fn->wifi_nan_disable_request);
+    populateStubFor(&hal_fn->wifi_nan_publish_request);
+    populateStubFor(&hal_fn->wifi_nan_publish_cancel_request);
+    populateStubFor(&hal_fn->wifi_nan_subscribe_request);
+    populateStubFor(&hal_fn->wifi_nan_subscribe_cancel_request);
+    populateStubFor(&hal_fn->wifi_nan_transmit_followup_request);
+    populateStubFor(&hal_fn->wifi_nan_stats_request);
+    populateStubFor(&hal_fn->wifi_nan_config_request);
+    populateStubFor(&hal_fn->wifi_nan_tca_request);
+    populateStubFor(&hal_fn->wifi_nan_beacon_sdf_payload_request);
+    populateStubFor(&hal_fn->wifi_nan_register_handler);
+    populateStubFor(&hal_fn->wifi_nan_get_version);
+    populateStubFor(&hal_fn->wifi_nan_get_capabilities);
+    populateStubFor(&hal_fn->wifi_nan_data_interface_create);
+    populateStubFor(&hal_fn->wifi_nan_data_interface_delete);
+    populateStubFor(&hal_fn->wifi_nan_data_request_initiator);
+    populateStubFor(&hal_fn->wifi_nan_data_indication_response);
+    populateStubFor(&hal_fn->wifi_nan_data_end);
+    populateStubFor(&hal_fn->wifi_get_packet_filter_capabilities);
+    populateStubFor(&hal_fn->wifi_set_packet_filter);
+    populateStubFor(&hal_fn->wifi_get_roaming_capabilities);
+    populateStubFor(&hal_fn->wifi_enable_firmware_roaming);
+    populateStubFor(&hal_fn->wifi_configure_roaming);
+    populateStubFor(&hal_fn->wifi_select_tx_power_scenario);
+    populateStubFor(&hal_fn->wifi_reset_tx_power_scenario);
+    populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
+    return true;
+}
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_legacy_hal_stubs.h b/wifi/1.2/default/wifi_legacy_hal_stubs.h
new file mode 100644
index 0000000..d560dd4
--- /dev/null
+++ b/wifi/1.2/default/wifi_legacy_hal_stubs.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_LEGACY_HAL_STUBS_H_
+#define WIFI_LEGACY_HAL_STUBS_H_
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace legacy_hal {
+#include <hardware_legacy/wifi_hal.h>
+
+bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
+}  // namespace legacy_hal
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_LEGACY_HAL_STUBS_H_
diff --git a/wifi/1.2/default/wifi_mode_controller.cpp b/wifi/1.2/default/wifi_mode_controller.cpp
new file mode 100644
index 0000000..c286d24
--- /dev/null
+++ b/wifi/1.2/default/wifi_mode_controller.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <private/android_filesystem_config.h>
+
+#include "wifi_mode_controller.h"
+
+using android::hardware::wifi::V1_0::IfaceType;
+using android::wifi_hal::DriverTool;
+
+namespace {
+int convertIfaceTypeToFirmwareMode(IfaceType type) {
+    int mode;
+    switch (type) {
+        case IfaceType::AP:
+            mode = DriverTool::kFirmwareModeAp;
+            break;
+        case IfaceType::P2P:
+            mode = DriverTool::kFirmwareModeP2p;
+            break;
+        case IfaceType::NAN:
+            // NAN is exposed in STA mode currently.
+            mode = DriverTool::kFirmwareModeSta;
+            break;
+        case IfaceType::STA:
+            mode = DriverTool::kFirmwareModeSta;
+            break;
+    }
+    return mode;
+}
+}  // namespace
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace mode_controller {
+
+WifiModeController::WifiModeController() : driver_tool_(new DriverTool) {}
+
+bool WifiModeController::isFirmwareModeChangeNeeded(IfaceType type) {
+    return driver_tool_->IsFirmwareModeChangeNeeded(
+        convertIfaceTypeToFirmwareMode(type));
+}
+
+bool WifiModeController::initialize() {
+    if (!driver_tool_->LoadDriver()) {
+        LOG(ERROR) << "Failed to load WiFi driver";
+        return false;
+    }
+    return true;
+}
+
+bool WifiModeController::changeFirmwareMode(IfaceType type) {
+    if (!driver_tool_->ChangeFirmwareMode(
+            convertIfaceTypeToFirmwareMode(type))) {
+        LOG(ERROR) << "Failed to change firmware mode";
+        return false;
+    }
+    return true;
+}
+
+bool WifiModeController::deinitialize() {
+    if (!driver_tool_->UnloadDriver()) {
+        LOG(ERROR) << "Failed to unload WiFi driver";
+        return false;
+    }
+    return true;
+}
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_mode_controller.h b/wifi/1.2/default/wifi_mode_controller.h
new file mode 100644
index 0000000..395aa5d
--- /dev/null
+++ b/wifi/1.2/default/wifi_mode_controller.h
@@ -0,0 +1,63 @@
+/*
+ * 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 WIFI_MODE_CONTROLLER_H_
+#define WIFI_MODE_CONTROLLER_H_
+
+#include <wifi_hal/driver_tool.h>
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+namespace mode_controller {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * Class that encapsulates all firmware mode configuration.
+ * This class will perform the necessary firmware reloads to put the chip in the
+ * required state (essentially a wrapper over DriverTool).
+ */
+class WifiModeController {
+   public:
+    WifiModeController();
+    virtual ~WifiModeController() = default;
+
+    // Checks if a firmware mode change is necessary to support the specified
+    // iface type operations.
+    virtual bool isFirmwareModeChangeNeeded(IfaceType type);
+    virtual bool initialize();
+    // Change the firmware mode to support the specified iface type operations.
+    virtual bool changeFirmwareMode(IfaceType type);
+    // Unload the driver. This should be invoked whenever |IWifi.stop()| is
+    // invoked.
+    virtual bool deinitialize();
+
+   private:
+    std::unique_ptr<wifi_hal::DriverTool> driver_tool_;
+};
+
+}  // namespace mode_controller
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_MODE_CONTROLLER_H_
diff --git a/wifi/1.2/default/wifi_nan_iface.cpp b/wifi/1.2/default/wifi_nan_iface.cpp
new file mode 100644
index 0000000..535e3d3
--- /dev/null
+++ b/wifi/1.2/default/wifi_nan_iface.cpp
@@ -0,0 +1,848 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_nan_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiNanIface::WifiNanIface(
+    const std::string& ifname,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {
+    // Register all the callbacks here. these should be valid for the lifetime
+    // of the object. Whenever the mode changes legacy HAL will remove
+    // all of these callbacks.
+    legacy_hal::NanCallbackHandlers callback_handlers;
+    android::wp<WifiNanIface> weak_ptr_this(this);
+
+    // Callback for response.
+    callback_handlers
+        .on_notify_response = [weak_ptr_this](
+                                  legacy_hal::transaction_id id,
+                                  const legacy_hal::NanResponseMsg& msg) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        WifiNanStatus wifiNanStatus;
+        if (!hidl_struct_util::convertLegacyNanResponseHeaderToHidl(
+                msg, &wifiNanStatus)) {
+            LOG(ERROR) << "Failed to convert nan response header";
+            return;
+        }
+
+        switch (msg.response_type) {
+            case legacy_hal::NAN_RESPONSE_ENABLED: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyEnableResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_DISABLED: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyDisableResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_PUBLISH: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyStartPublishResponse(
+                                 id, wifiNanStatus,
+                                 msg.body.publish_response.publish_id)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_PUBLISH_CANCEL: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyStopPublishResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_TRANSMIT_FOLLOWUP: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyTransmitFollowupResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_SUBSCRIBE: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyStartSubscribeResponse(
+                                 id, wifiNanStatus,
+                                 msg.body.subscribe_response.subscribe_id)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_SUBSCRIBE_CANCEL: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyStopSubscribeResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_CONFIG: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback->notifyConfigResponse(id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_GET_CAPABILITIES: {
+                NanCapabilities hidl_struct;
+                if (!hidl_struct_util::
+                        convertLegacyNanCapabilitiesResponseToHidl(
+                            msg.body.nan_capabilities, &hidl_struct)) {
+                    LOG(ERROR) << "Failed to convert nan capabilities response";
+                    return;
+                }
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyCapabilitiesResponse(id, wifiNanStatus,
+                                                          hidl_struct)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INTERFACE_CREATE: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyCreateDataInterfaceResponse(id,
+                                                                 wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INTERFACE_DELETE: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyDeleteDataInterfaceResponse(id,
+                                                                 wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_INITIATOR_RESPONSE: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyInitiateDataPathResponse(
+                                 id, wifiNanStatus,
+                                 msg.body.data_request_response.ndp_instance_id)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_RESPONDER_RESPONSE: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyRespondToDataPathIndicationResponse(
+                                 id, wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_DP_END: {
+                for (const auto& callback :
+                     shared_ptr_this->getEventCallbacks()) {
+                    if (!callback
+                             ->notifyTerminateDataPathResponse(id,
+                                                               wifiNanStatus)
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+                break;
+            }
+            case legacy_hal::NAN_RESPONSE_BEACON_SDF_PAYLOAD:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_TCA:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_STATS:
+            /* fall through */
+            case legacy_hal::NAN_RESPONSE_ERROR:
+            /* fall through */
+            default:
+                LOG(ERROR) << "Unknown or unhandled response type: "
+                           << msg.response_type;
+                return;
+        }
+    };
+
+    callback_handlers.on_event_disc_eng_event =
+        [weak_ptr_this](const legacy_hal::NanDiscEngEventInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            NanClusterEventInd hidl_struct;
+            // event types defined identically - hence can be cast
+            hidl_struct.eventType = (NanClusterEventType)msg.event_type;
+            hidl_struct.addr = msg.data.mac_addr.addr;
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventClusterEvent(hidl_struct).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_disabled =
+        [weak_ptr_this](const legacy_hal::NanDisabledInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            WifiNanStatus status;
+            hidl_struct_util::convertToWifiNanStatus(
+                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventDisabled(status).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_publish_terminated =
+        [weak_ptr_this](const legacy_hal::NanPublishTerminatedInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            WifiNanStatus status;
+            hidl_struct_util::convertToWifiNanStatus(
+                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventPublishTerminated(msg.publish_id, status)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_subscribe_terminated =
+        [weak_ptr_this](const legacy_hal::NanSubscribeTerminatedInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            WifiNanStatus status;
+            hidl_struct_util::convertToWifiNanStatus(
+                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback
+                         ->eventSubscribeTerminated(msg.subscribe_id, status)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_match =
+        [weak_ptr_this](const legacy_hal::NanMatchInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            NanMatchInd hidl_struct;
+            if (!hidl_struct_util::convertLegacyNanMatchIndToHidl(
+                    msg, &hidl_struct)) {
+                LOG(ERROR) << "Failed to convert nan capabilities response";
+                return;
+            }
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventMatch(hidl_struct).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_match_expired =
+        [weak_ptr_this](const legacy_hal::NanMatchExpiredInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback
+                         ->eventMatchExpired(msg.publish_subscribe_id,
+                                             msg.requestor_instance_id)
+                         .isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_followup =
+        [weak_ptr_this](const legacy_hal::NanFollowupInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            NanFollowupReceivedInd hidl_struct;
+            if (!hidl_struct_util::convertLegacyNanFollowupIndToHidl(
+                    msg, &hidl_struct)) {
+                LOG(ERROR) << "Failed to convert nan capabilities response";
+                return;
+            }
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventFollowupReceived(hidl_struct).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_transmit_follow_up =
+        [weak_ptr_this](const legacy_hal::NanTransmitFollowupInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            WifiNanStatus status;
+            hidl_struct_util::convertToWifiNanStatus(
+                msg.reason, msg.nan_reason, sizeof(msg.nan_reason), &status);
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventTransmitFollowup(msg.id, status).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_data_path_request =
+        [weak_ptr_this](const legacy_hal::NanDataPathRequestInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            NanDataPathRequestInd hidl_struct;
+            if (!hidl_struct_util::convertLegacyNanDataPathRequestIndToHidl(
+                    msg, &hidl_struct)) {
+                LOG(ERROR) << "Failed to convert nan capabilities response";
+                return;
+            }
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventDataPathRequest(hidl_struct).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_data_path_confirm =
+        [weak_ptr_this](const legacy_hal::NanDataPathConfirmInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            NanDataPathConfirmInd hidl_struct;
+            if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(
+                    msg, &hidl_struct)) {
+                LOG(ERROR) << "Failed to convert nan capabilities response";
+                return;
+            }
+
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->eventDataPathConfirm_1_2(hidl_struct).isOk()) {
+                    LOG(ERROR) << "Failed to invoke the callback";
+                }
+            }
+        };
+
+    callback_handlers.on_event_data_path_end =
+        [weak_ptr_this](const legacy_hal::NanDataPathEndInd& msg) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                for (int i = 0; i < msg.num_ndp_instances; ++i) {
+                    if (!callback
+                             ->eventDataPathTerminated(msg.ndp_instance_id[i])
+                             .isOk()) {
+                        LOG(ERROR) << "Failed to invoke the callback";
+                    }
+                }
+            }
+        };
+
+    callback_handlers.on_event_beacon_sdf_payload =
+        [weak_ptr_this](const legacy_hal::NanBeaconSdfPayloadInd& /* msg */) {
+            LOG(ERROR) << "on_event_beacon_sdf_payload - should not be called";
+        };
+
+    callback_handlers.on_event_range_request =
+        [weak_ptr_this](const legacy_hal::NanRangeRequestInd& /* msg */) {
+            LOG(ERROR) << "on_event_range_request - should not be called";
+        };
+
+    callback_handlers.on_event_range_report =
+        [weak_ptr_this](const legacy_hal::NanRangeReportInd& /* msg */) {
+            LOG(ERROR) << "on_event_range_report - should not be called";
+        };
+
+    callback_handlers
+        .on_event_schedule_update = [weak_ptr_this](
+                                        const legacy_hal::
+                                            NanDataPathScheduleUpdateInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        NanDataPathScheduleUpdateInd hidl_struct;
+        if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
+                msg, &hidl_struct)) {
+            LOG(ERROR) << "Failed to convert nan capabilities response";
+            return;
+        }
+
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventDataPathScheduleUpdate(hidl_struct).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
+
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_,
+                                                        callback_handlers);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR) << "Failed to register nan callbacks. Invalidating object";
+        invalidate();
+    }
+}
+
+void WifiNanIface::invalidate() {
+    // send commands to HAL to actually disable and destroy interfaces
+    legacy_hal_.lock()->nanDisableRequest(ifname_, 0xFFFF);
+    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFE, "aware_data0");
+    legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, 0xFFFD, "aware_data1");
+
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    is_valid_ = false;
+}
+
+bool WifiNanIface::isValid() { return is_valid_; }
+
+std::string WifiNanIface::getName() { return ifname_; }
+
+std::set<sp<IWifiNanIfaceEventCallback>> WifiNanIface::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiNanIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiNanIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiNanIface::registerEventCallback(
+    const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::registerEventCallbackInternal,
+                           hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::getCapabilitiesRequest(
+    uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::getCapabilitiesRequestInternal,
+                           hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiNanIface::enableRequest(uint16_t cmd_id,
+                                         const NanEnableRequest& msg,
+                                         enableRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequestInternal, hidl_status_cb,
+                           cmd_id, msg);
+}
+
+Return<void> WifiNanIface::configRequest(uint16_t cmd_id,
+                                         const NanConfigRequest& msg,
+                                         configRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequestInternal, hidl_status_cb,
+                           cmd_id, msg);
+}
+
+Return<void> WifiNanIface::disableRequest(uint16_t cmd_id,
+                                          disableRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::disableRequestInternal,
+                           hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiNanIface::startPublishRequest(
+    uint16_t cmd_id, const NanPublishRequest& msg,
+    startPublishRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::startPublishRequestInternal,
+                           hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::stopPublishRequest(
+    uint16_t cmd_id, uint8_t sessionId, stopPublishRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::stopPublishRequestInternal,
+                           hidl_status_cb, cmd_id, sessionId);
+}
+
+Return<void> WifiNanIface::startSubscribeRequest(
+    uint16_t cmd_id, const NanSubscribeRequest& msg,
+    startSubscribeRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::startSubscribeRequestInternal,
+                           hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::stopSubscribeRequest(
+    uint16_t cmd_id, uint8_t sessionId,
+    stopSubscribeRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::stopSubscribeRequestInternal,
+                           hidl_status_cb, cmd_id, sessionId);
+}
+
+Return<void> WifiNanIface::transmitFollowupRequest(
+    uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
+    transmitFollowupRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::transmitFollowupRequestInternal,
+                           hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::createDataInterfaceRequest(
+    uint16_t cmd_id, const hidl_string& iface_name,
+    createDataInterfaceRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::createDataInterfaceRequestInternal,
+                           hidl_status_cb, cmd_id, iface_name);
+}
+
+Return<void> WifiNanIface::deleteDataInterfaceRequest(
+    uint16_t cmd_id, const hidl_string& iface_name,
+    deleteDataInterfaceRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::deleteDataInterfaceRequestInternal,
+                           hidl_status_cb, cmd_id, iface_name);
+}
+
+Return<void> WifiNanIface::initiateDataPathRequest(
+    uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
+    initiateDataPathRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::initiateDataPathRequestInternal,
+                           hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::respondToDataPathIndicationRequest(
+    uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
+    respondToDataPathIndicationRequest_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+        &WifiNanIface::respondToDataPathIndicationRequestInternal,
+        hidl_status_cb, cmd_id, msg);
+}
+
+Return<void> WifiNanIface::terminateDataPathRequest(
+    uint16_t cmd_id, uint32_t ndpInstanceId,
+    terminateDataPathRequest_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::terminateDataPathRequestInternal,
+                           hidl_status_cb, cmd_id, ndpInstanceId);
+}
+
+Return<void> WifiNanIface::registerEventCallback_1_2(
+    const sp<IWifiNanIfaceEventCallback>& callback,
+    registerEventCallback_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::registerEventCallback_1_2Internal,
+                           hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::enableRequest_1_2(
+    uint16_t cmd_id, const NanEnableRequest& msg1,
+    const NanConfigRequestSupplemental& msg2,
+    enableRequest_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequest_1_2Internal,
+                           hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_2(
+    uint16_t cmd_id, const NanConfigRequest& msg1,
+    const NanConfigRequestSupplemental& msg2,
+    configRequest_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequest_1_2Internal,
+                           hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiNanIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::NAN};
+}
+
+WifiStatus WifiNanIface::registerEventCallbackInternal(
+    const sp<V1_0::IWifiNanIfaceEventCallback>& /*callback*/) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanGetCapabilities(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::enableRequestInternal(
+    uint16_t /* cmd_id */, const NanEnableRequest& /* msg */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::configRequestInternal(
+    uint16_t /* cmd_id */, const NanConfigRequest& /* msg */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDisableRequest(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startPublishRequestInternal(
+    uint16_t cmd_id, const NanPublishRequest& msg) {
+    legacy_hal::NanPublishRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanPublishRequestToLegacy(msg,
+                                                                &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanPublishRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::stopPublishRequestInternal(uint16_t cmd_id,
+                                                    uint8_t sessionId) {
+    legacy_hal::NanPublishCancelRequest legacy_msg;
+    legacy_msg.publish_id = sessionId;
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanPublishCancelRequest(ifname_, cmd_id,
+                                                    legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::startSubscribeRequestInternal(
+    uint16_t cmd_id, const NanSubscribeRequest& msg) {
+    legacy_hal::NanSubscribeRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanSubscribeRequestToLegacy(
+            msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanSubscribeRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::stopSubscribeRequestInternal(uint16_t cmd_id,
+                                                      uint8_t sessionId) {
+    legacy_hal::NanSubscribeCancelRequest legacy_msg;
+    legacy_msg.subscribe_id = sessionId;
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanSubscribeCancelRequest(ifname_, cmd_id,
+                                                      legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::transmitFollowupRequestInternal(
+    uint16_t cmd_id, const NanTransmitFollowupRequest& msg) {
+    legacy_hal::NanTransmitFollowupRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanTransmitFollowupRequestToLegacy(
+            msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanTransmitFollowupRequest(ifname_, cmd_id,
+                                                       legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::createDataInterfaceRequestInternal(
+    uint16_t cmd_id, const std::string& iface_name) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDataInterfaceCreate(ifname_, cmd_id, iface_name);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::deleteDataInterfaceRequestInternal(
+    uint16_t cmd_id, const std::string& iface_name) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDataInterfaceDelete(ifname_, cmd_id, iface_name);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::initiateDataPathRequestInternal(
+    uint16_t cmd_id, const NanInitiateDataPathRequest& msg) {
+    legacy_hal::NanDataPathInitiatorRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanDataPathInitiatorRequestToLegacy(
+            msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDataRequestInitiator(ifname_, cmd_id,
+                                                    legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::respondToDataPathIndicationRequestInternal(
+    uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg) {
+    legacy_hal::NanDataPathIndicationResponse legacy_msg;
+    if (!hidl_struct_util::convertHidlNanDataPathIndicationResponseToLegacy(
+            msg, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDataIndicationResponse(ifname_, cmd_id,
+                                                      legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+WifiStatus WifiNanIface::terminateDataPathRequestInternal(
+    uint16_t cmd_id, uint32_t ndpInstanceId) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanDataEnd(ifname_, cmd_id, ndpInstanceId);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
+    const sp<IWifiNanIfaceEventCallback>& callback) {
+    if (!event_cb_handler_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_2Internal(
+    uint16_t cmd_id, const NanEnableRequest& msg1,
+    const NanConfigRequestSupplemental& msg2) {
+    legacy_hal::NanEnableRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanEnableRequest_1_2ToLegacy(
+            msg1, msg2, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::configRequest_1_2Internal(
+    uint16_t cmd_id, const NanConfigRequest& msg1,
+    const NanConfigRequestSupplemental& msg2) {
+    legacy_hal::NanConfigRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanConfigRequest_1_2ToLegacy(
+            msg1, msg2, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_nan_iface.h b/wifi/1.2/default/wifi_nan_iface.h
new file mode 100644
index 0000000..a2dcf3a
--- /dev/null
+++ b/wifi/1.2/default/wifi_nan_iface.h
@@ -0,0 +1,160 @@
+/*
+ * 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 WIFI_NAN_IFACE_H_
+#define WIFI_NAN_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
+#include <android/hardware/wifi/1.2/IWifiNanIface.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a NAN Iface instance.
+ */
+class WifiNanIface : public V1_2::IWifiNanIface {
+   public:
+    WifiNanIface(const std::string& ifname,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+    Return<void> registerEventCallback(
+        const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
+        registerEventCallback_cb hidl_status_cb) override;
+    Return<void> getCapabilitiesRequest(
+        uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) override;
+    Return<void> enableRequest(uint16_t cmd_id, const NanEnableRequest& msg,
+                               enableRequest_cb hidl_status_cb) override;
+    Return<void> configRequest(uint16_t cmd_id, const NanConfigRequest& msg,
+                               configRequest_cb hidl_status_cb) override;
+    Return<void> disableRequest(uint16_t cmd_id,
+                                disableRequest_cb hidl_status_cb) override;
+    Return<void> startPublishRequest(
+        uint16_t cmd_id, const NanPublishRequest& msg,
+        startPublishRequest_cb hidl_status_cb) override;
+    Return<void> stopPublishRequest(
+        uint16_t cmd_id, uint8_t sessionId,
+        stopPublishRequest_cb hidl_status_cb) override;
+    Return<void> startSubscribeRequest(
+        uint16_t cmd_id, const NanSubscribeRequest& msg,
+        startSubscribeRequest_cb hidl_status_cb) override;
+    Return<void> stopSubscribeRequest(
+        uint16_t cmd_id, uint8_t sessionId,
+        stopSubscribeRequest_cb hidl_status_cb) override;
+    Return<void> transmitFollowupRequest(
+        uint16_t cmd_id, const NanTransmitFollowupRequest& msg,
+        transmitFollowupRequest_cb hidl_status_cb) override;
+    Return<void> createDataInterfaceRequest(
+        uint16_t cmd_id, const hidl_string& iface_name,
+        createDataInterfaceRequest_cb hidl_status_cb) override;
+    Return<void> deleteDataInterfaceRequest(
+        uint16_t cmd_id, const hidl_string& iface_name,
+        deleteDataInterfaceRequest_cb hidl_status_cb) override;
+    Return<void> initiateDataPathRequest(
+        uint16_t cmd_id, const NanInitiateDataPathRequest& msg,
+        initiateDataPathRequest_cb hidl_status_cb) override;
+    Return<void> respondToDataPathIndicationRequest(
+        uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg,
+        respondToDataPathIndicationRequest_cb hidl_status_cb) override;
+    Return<void> terminateDataPathRequest(
+        uint16_t cmd_id, uint32_t ndpInstanceId,
+        terminateDataPathRequest_cb hidl_status_cb) override;
+
+    Return<void> registerEventCallback_1_2(
+        const sp<IWifiNanIfaceEventCallback>& callback,
+        registerEventCallback_1_2_cb hidl_status_cb) override;
+    Return<void> enableRequest_1_2(
+        uint16_t cmd_id, const NanEnableRequest& msg1,
+        const NanConfigRequestSupplemental& msg2,
+        enableRequest_1_2_cb hidl_status_cb) override;
+    Return<void> configRequest_1_2(
+        uint16_t cmd_id, const NanConfigRequest& msg1,
+        const NanConfigRequestSupplemental& msg2,
+        configRequest_1_2_cb hidl_status_cb) override;
+
+   private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+    WifiStatus registerEventCallbackInternal(
+        const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
+    WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
+    WifiStatus enableRequestInternal(uint16_t cmd_id,
+                                     const NanEnableRequest& msg);
+    WifiStatus configRequestInternal(uint16_t cmd_id,
+                                     const NanConfigRequest& msg);
+    WifiStatus disableRequestInternal(uint16_t cmd_id);
+    WifiStatus startPublishRequestInternal(uint16_t cmd_id,
+                                           const NanPublishRequest& msg);
+    WifiStatus stopPublishRequestInternal(uint16_t cmd_id, uint8_t sessionId);
+    WifiStatus startSubscribeRequestInternal(uint16_t cmd_id,
+                                             const NanSubscribeRequest& msg);
+    WifiStatus stopSubscribeRequestInternal(uint16_t cmd_id, uint8_t sessionId);
+    WifiStatus transmitFollowupRequestInternal(
+        uint16_t cmd_id, const NanTransmitFollowupRequest& msg);
+    WifiStatus createDataInterfaceRequestInternal(
+        uint16_t cmd_id, const std::string& iface_name);
+    WifiStatus deleteDataInterfaceRequestInternal(
+        uint16_t cmd_id, const std::string& iface_name);
+    WifiStatus initiateDataPathRequestInternal(
+        uint16_t cmd_id, const NanInitiateDataPathRequest& msg);
+    WifiStatus respondToDataPathIndicationRequestInternal(
+        uint16_t cmd_id, const NanRespondToDataPathIndicationRequest& msg);
+    WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id,
+                                                uint32_t ndpInstanceId);
+
+    WifiStatus registerEventCallback_1_2Internal(
+        const sp<IWifiNanIfaceEventCallback>& callback);
+    WifiStatus enableRequest_1_2Internal(
+        uint16_t cmd_id, const NanEnableRequest& msg1,
+        const NanConfigRequestSupplemental& msg2);
+    WifiStatus configRequest_1_2Internal(
+        uint16_t cmd_id, const NanConfigRequest& msg,
+        const NanConfigRequestSupplemental& msg2);
+
+    std::set<sp<IWifiNanIfaceEventCallback>> getEventCallbacks();
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    bool is_valid_;
+    hidl_callback_util::HidlCallbackHandler<IWifiNanIfaceEventCallback>
+        event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiNanIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_NAN_IFACE_H_
diff --git a/wifi/1.2/default/wifi_p2p_iface.cpp b/wifi/1.2/default/wifi_p2p_iface.cpp
new file mode 100644
index 0000000..92bbaee
--- /dev/null
+++ b/wifi/1.2/default/wifi_p2p_iface.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "wifi_p2p_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiP2pIface::WifiP2pIface(
+    const std::string& ifname,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {}
+
+void WifiP2pIface::invalidate() {
+    legacy_hal_.reset();
+    is_valid_ = false;
+}
+
+bool WifiP2pIface::isValid() { return is_valid_; }
+
+std::string WifiP2pIface::getName() { return ifname_; }
+
+Return<void> WifiP2pIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiP2pIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiP2pIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiP2pIface::getTypeInternal, hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiP2pIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiP2pIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::P2P};
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_p2p_iface.h b/wifi/1.2/default/wifi_p2p_iface.h
new file mode 100644
index 0000000..76120b1
--- /dev/null
+++ b/wifi/1.2/default/wifi_p2p_iface.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WIFI_P2P_IFACE_H_
+#define WIFI_P2P_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiP2pIface.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a P2P Iface instance.
+ */
+class WifiP2pIface : public V1_0::IWifiP2pIface {
+   public:
+    WifiP2pIface(const std::string& ifname,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+
+   private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiP2pIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_P2P_IFACE_H_
diff --git a/wifi/1.2/default/wifi_rtt_controller.cpp b/wifi/1.2/default/wifi_rtt_controller.cpp
new file mode 100644
index 0000000..b68445b
--- /dev/null
+++ b/wifi/1.2/default/wifi_rtt_controller.cpp
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_rtt_controller.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiRttController::WifiRttController(
+    const std::string& iface_name, const sp<IWifiIface>& bound_iface,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(iface_name),
+      bound_iface_(bound_iface),
+      legacy_hal_(legacy_hal),
+      is_valid_(true) {}
+
+void WifiRttController::invalidate() {
+    legacy_hal_.reset();
+    event_callbacks_.clear();
+    is_valid_ = false;
+}
+
+bool WifiRttController::isValid() { return is_valid_; }
+
+std::vector<sp<IWifiRttControllerEventCallback>>
+WifiRttController::getEventCallbacks() {
+    return event_callbacks_;
+}
+
+Return<void> WifiRttController::getBoundIface(getBoundIface_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::getBoundIfaceInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::registerEventCallback(
+    const sp<IWifiRttControllerEventCallback>& callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this,
+                           WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::registerEventCallbackInternal,
+                           hidl_status_cb, callback);
+}
+
+Return<void> WifiRttController::rangeRequest(
+    uint32_t cmd_id, const hidl_vec<RttConfig>& rtt_configs,
+    rangeRequest_cb hidl_status_cb) {
+    return validateAndCall(this,
+                           WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+                           &WifiRttController::rangeRequestInternal,
+                           hidl_status_cb, cmd_id, rtt_configs);
+}
+
+Return<void> WifiRttController::rangeCancel(
+    uint32_t cmd_id, const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
+    rangeCancel_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::rangeCancelInternal, hidl_status_cb, cmd_id, addrs);
+}
+
+Return<void> WifiRttController::getCapabilities(
+    getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::getCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::setLci(uint32_t cmd_id,
+                                       const RttLciInformation& lci,
+                                       setLci_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::setLciInternal, hidl_status_cb, cmd_id, lci);
+}
+
+Return<void> WifiRttController::setLcr(uint32_t cmd_id,
+                                       const RttLcrInformation& lcr,
+                                       setLcr_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::setLcrInternal, hidl_status_cb, cmd_id, lcr);
+}
+
+Return<void> WifiRttController::getResponderInfo(
+    getResponderInfo_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::getResponderInfoInternal, hidl_status_cb);
+}
+
+Return<void> WifiRttController::enableResponder(
+    uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+    uint32_t max_duration_seconds, const RttResponder& info,
+    enableResponder_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::enableResponderInternal, hidl_status_cb, cmd_id,
+        channel_hint, max_duration_seconds, info);
+}
+
+Return<void> WifiRttController::disableResponder(
+    uint32_t cmd_id, disableResponder_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_RTT_CONTROLLER_INVALID,
+        &WifiRttController::disableResponderInternal, hidl_status_cb, cmd_id);
+}
+
+std::pair<WifiStatus, sp<IWifiIface>>
+WifiRttController::getBoundIfaceInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), bound_iface_};
+}
+
+WifiStatus WifiRttController::registerEventCallbackInternal(
+    const sp<IWifiRttControllerEventCallback>& callback) {
+    // TODO(b/31632518): remove the callback when the client is destroyed
+    event_callbacks_.emplace_back(callback);
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiRttController::rangeRequestInternal(
+    uint32_t cmd_id, const std::vector<RttConfig>& rtt_configs) {
+    std::vector<legacy_hal::wifi_rtt_config> legacy_configs;
+    if (!hidl_struct_util::convertHidlVectorOfRttConfigToLegacy(
+            rtt_configs, &legacy_configs)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    android::wp<WifiRttController> weak_ptr_this(this);
+    const auto& on_results_callback =
+        [weak_ptr_this](
+            legacy_hal::wifi_request_id id,
+            const std::vector<const legacy_hal::wifi_rtt_result*>& results) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            std::vector<RttResult> hidl_results;
+            if (!hidl_struct_util::convertLegacyVectorOfRttResultToHidl(
+                    results, &hidl_results)) {
+                LOG(ERROR) << "Failed to convert rtt results to HIDL structs";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                callback->onResults(id, hidl_results);
+            }
+        };
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->startRttRangeRequest(
+            ifname_, cmd_id, legacy_configs, on_results_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::rangeCancelInternal(
+    uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs) {
+    std::vector<std::array<uint8_t, 6>> legacy_addrs;
+    for (const auto& addr : addrs) {
+        legacy_addrs.push_back(addr);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->cancelRttRangeRequest(ifname_, cmd_id,
+                                                  legacy_addrs);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, RttCapabilities>
+WifiRttController::getCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_rtt_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) =
+        legacy_hal_.lock()->getRttCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    RttCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyRttCapabilitiesToHidl(legacy_caps,
+                                                              &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiRttController::setLciInternal(uint32_t cmd_id,
+                                             const RttLciInformation& lci) {
+    legacy_hal::wifi_lci_information legacy_lci;
+    if (!hidl_struct_util::convertHidlRttLciInformationToLegacy(lci,
+                                                                &legacy_lci)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setRttLci(ifname_, cmd_id, legacy_lci);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::setLcrInternal(uint32_t cmd_id,
+                                             const RttLcrInformation& lcr) {
+    legacy_hal::wifi_lcr_information legacy_lcr;
+    if (!hidl_struct_util::convertHidlRttLcrInformationToLegacy(lcr,
+                                                                &legacy_lcr)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setRttLcr(ifname_, cmd_id, legacy_lcr);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, RttResponder>
+WifiRttController::getResponderInfoInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_rtt_responder legacy_responder;
+    std::tie(legacy_status, legacy_responder) =
+        legacy_hal_.lock()->getRttResponderInfo(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    RttResponder hidl_responder;
+    if (!hidl_struct_util::convertLegacyRttResponderToHidl(legacy_responder,
+                                                           &hidl_responder)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_responder};
+}
+
+WifiStatus WifiRttController::enableResponderInternal(
+    uint32_t cmd_id, const WifiChannelInfo& channel_hint,
+    uint32_t max_duration_seconds, const RttResponder& info) {
+    legacy_hal::wifi_channel_info legacy_channel_info;
+    if (!hidl_struct_util::convertHidlWifiChannelInfoToLegacy(
+            channel_hint, &legacy_channel_info)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_rtt_responder legacy_responder;
+    if (!hidl_struct_util::convertHidlRttResponderToLegacy(info,
+                                                           &legacy_responder)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->enableRttResponder(
+            ifname_, cmd_id, legacy_channel_info, max_duration_seconds,
+            legacy_responder);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiRttController::disableResponderInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->disableRttResponder(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_rtt_controller.h b/wifi/1.2/default/wifi_rtt_controller.h
new file mode 100644
index 0000000..1ab01e1
--- /dev/null
+++ b/wifi/1.2/default/wifi_rtt_controller.h
@@ -0,0 +1,105 @@
+/*
+ * 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 WIFI_RTT_CONTROLLER_H_
+#define WIFI_RTT_CONTROLLER_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiIface.h>
+#include <android/hardware/wifi/1.0/IWifiRttController.h>
+#include <android/hardware/wifi/1.0/IWifiRttControllerEventCallback.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+
+/**
+ * HIDL interface object used to control all RTT operations.
+ */
+class WifiRttController : public V1_0::IWifiRttController {
+   public:
+    WifiRttController(
+        const std::string& iface_name, const sp<IWifiIface>& bound_iface,
+        const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::vector<sp<IWifiRttControllerEventCallback>> getEventCallbacks();
+
+    // HIDL methods exposed.
+    Return<void> getBoundIface(getBoundIface_cb hidl_status_cb) override;
+    Return<void> registerEventCallback(
+        const sp<IWifiRttControllerEventCallback>& callback,
+        registerEventCallback_cb hidl_status_cb) override;
+    Return<void> rangeRequest(uint32_t cmd_id,
+                              const hidl_vec<RttConfig>& rtt_configs,
+                              rangeRequest_cb hidl_status_cb) override;
+    Return<void> rangeCancel(uint32_t cmd_id,
+                             const hidl_vec<hidl_array<uint8_t, 6>>& addrs,
+                             rangeCancel_cb hidl_status_cb) override;
+    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+    Return<void> setLci(uint32_t cmd_id, const RttLciInformation& lci,
+                        setLci_cb hidl_status_cb) override;
+    Return<void> setLcr(uint32_t cmd_id, const RttLcrInformation& lcr,
+                        setLcr_cb hidl_status_cb) override;
+    Return<void> getResponderInfo(getResponderInfo_cb hidl_status_cb) override;
+    Return<void> enableResponder(uint32_t cmd_id,
+                                 const WifiChannelInfo& channel_hint,
+                                 uint32_t max_duration_seconds,
+                                 const RttResponder& info,
+                                 enableResponder_cb hidl_status_cb) override;
+    Return<void> disableResponder(uint32_t cmd_id,
+                                  disableResponder_cb hidl_status_cb) override;
+
+   private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, sp<IWifiIface>> getBoundIfaceInternal();
+    WifiStatus registerEventCallbackInternal(
+        const sp<IWifiRttControllerEventCallback>& callback);
+    WifiStatus rangeRequestInternal(uint32_t cmd_id,
+                                    const std::vector<RttConfig>& rtt_configs);
+    WifiStatus rangeCancelInternal(
+        uint32_t cmd_id, const std::vector<hidl_array<uint8_t, 6>>& addrs);
+    std::pair<WifiStatus, RttCapabilities> getCapabilitiesInternal();
+    WifiStatus setLciInternal(uint32_t cmd_id, const RttLciInformation& lci);
+    WifiStatus setLcrInternal(uint32_t cmd_id, const RttLcrInformation& lcr);
+    std::pair<WifiStatus, RttResponder> getResponderInfoInternal();
+    WifiStatus enableResponderInternal(uint32_t cmd_id,
+                                       const WifiChannelInfo& channel_hint,
+                                       uint32_t max_duration_seconds,
+                                       const RttResponder& info);
+    WifiStatus disableResponderInternal(uint32_t cmd_id);
+
+    std::string ifname_;
+    sp<IWifiIface> bound_iface_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    std::vector<sp<IWifiRttControllerEventCallback>> event_callbacks_;
+    bool is_valid_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiRttController);
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_RTT_CONTROLLER_H_
diff --git a/wifi/1.2/default/wifi_sta_iface.cpp b/wifi/1.2/default/wifi_sta_iface.cpp
new file mode 100644
index 0000000..6faf009
--- /dev/null
+++ b/wifi/1.2/default/wifi_sta_iface.cpp
@@ -0,0 +1,585 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include "hidl_return_util.h"
+#include "hidl_struct_util.h"
+#include "wifi_sta_iface.h"
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using hidl_return_util::validateAndCall;
+
+WifiStaIface::WifiStaIface(
+    const std::string& ifname,
+    const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal)
+    : ifname_(ifname), legacy_hal_(legacy_hal), is_valid_(true) {
+    // Turn on DFS channel usage for STA iface.
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setDfsFlag(ifname_, true);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        LOG(ERROR)
+            << "Failed to set DFS flag; DFS channels may be unavailable.";
+    }
+}
+
+void WifiStaIface::invalidate() {
+    legacy_hal_.reset();
+    event_cb_handler_.invalidate();
+    is_valid_ = false;
+}
+
+bool WifiStaIface::isValid() { return is_valid_; }
+
+std::string WifiStaIface::getName() { return ifname_; }
+
+std::set<sp<IWifiStaIfaceEventCallback>> WifiStaIface::getEventCallbacks() {
+    return event_cb_handler_.getCallbacks();
+}
+
+Return<void> WifiStaIface::getName(getName_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getNameInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getType(getType_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getTypeInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::registerEventCallback(
+    const sp<IWifiStaIfaceEventCallback>& callback,
+    registerEventCallback_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::registerEventCallbackInternal,
+                           hidl_status_cb, callback);
+}
+
+Return<void> WifiStaIface::getCapabilities(getCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getCapabilitiesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getApfPacketFilterCapabilities(
+    getApfPacketFilterCapabilities_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+        &WifiStaIface::getApfPacketFilterCapabilitiesInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::installApfPacketFilter(
+    uint32_t cmd_id, const hidl_vec<uint8_t>& program,
+    installApfPacketFilter_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::installApfPacketFilterInternal,
+                           hidl_status_cb, cmd_id, program);
+}
+
+Return<void> WifiStaIface::getBackgroundScanCapabilities(
+    getBackgroundScanCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getBackgroundScanCapabilitiesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getValidFrequenciesForBand(
+    WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getValidFrequenciesForBandInternal,
+                           hidl_status_cb, band);
+}
+
+Return<void> WifiStaIface::startBackgroundScan(
+    uint32_t cmd_id, const StaBackgroundScanParameters& params,
+    startBackgroundScan_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startBackgroundScanInternal,
+                           hidl_status_cb, cmd_id, params);
+}
+
+Return<void> WifiStaIface::stopBackgroundScan(
+    uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopBackgroundScanInternal,
+                           hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::enableLinkLayerStatsCollection(
+    bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+        &WifiStaIface::enableLinkLayerStatsCollectionInternal, hidl_status_cb,
+        debug);
+}
+
+Return<void> WifiStaIface::disableLinkLayerStatsCollection(
+    disableLinkLayerStatsCollection_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+        &WifiStaIface::disableLinkLayerStatsCollectionInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getLinkLayerStats(
+    getLinkLayerStats_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getLinkLayerStatsInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::startRssiMonitoring(
+    uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
+    startRssiMonitoring_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startRssiMonitoringInternal,
+                           hidl_status_cb, cmd_id, max_rssi, min_rssi);
+}
+
+Return<void> WifiStaIface::stopRssiMonitoring(
+    uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopRssiMonitoringInternal,
+                           hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::getRoamingCapabilities(
+    getRoamingCapabilities_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getRoamingCapabilitiesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::configureRoaming(
+    const StaRoamingConfig& config, configureRoaming_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::configureRoamingInternal,
+                           hidl_status_cb, config);
+}
+
+Return<void> WifiStaIface::setRoamingState(StaRoamingState state,
+                                           setRoamingState_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setRoamingStateInternal,
+                           hidl_status_cb, state);
+}
+
+Return<void> WifiStaIface::enableNdOffload(bool enable,
+                                           enableNdOffload_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::enableNdOffloadInternal,
+                           hidl_status_cb, enable);
+}
+
+Return<void> WifiStaIface::startSendingKeepAlivePackets(
+    uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
+    uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
+    const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
+    startSendingKeepAlivePackets_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::startSendingKeepAlivePacketsInternal,
+                           hidl_status_cb, cmd_id, ip_packet_data, ether_type,
+                           src_address, dst_address, period_in_ms);
+}
+
+Return<void> WifiStaIface::stopSendingKeepAlivePackets(
+    uint32_t cmd_id, stopSendingKeepAlivePackets_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::stopSendingKeepAlivePacketsInternal,
+                           hidl_status_cb, cmd_id);
+}
+
+Return<void> WifiStaIface::setScanningMacOui(
+    const hidl_array<uint8_t, 3>& oui, setScanningMacOui_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::setScanningMacOuiInternal,
+                           hidl_status_cb, oui);
+}
+
+Return<void> WifiStaIface::startDebugPacketFateMonitoring(
+    startDebugPacketFateMonitoring_cb hidl_status_cb) {
+    return validateAndCall(
+        this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+        &WifiStaIface::startDebugPacketFateMonitoringInternal, hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getDebugTxPacketFates(
+    getDebugTxPacketFates_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getDebugTxPacketFatesInternal,
+                           hidl_status_cb);
+}
+
+Return<void> WifiStaIface::getDebugRxPacketFates(
+    getDebugRxPacketFates_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getDebugRxPacketFatesInternal,
+                           hidl_status_cb);
+}
+
+std::pair<WifiStatus, std::string> WifiStaIface::getNameInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
+}
+
+std::pair<WifiStatus, IfaceType> WifiStaIface::getTypeInternal() {
+    return {createWifiStatus(WifiStatusCode::SUCCESS), IfaceType::STA};
+}
+
+WifiStatus WifiStaIface::registerEventCallbackInternal(
+    const sp<IWifiStaIfaceEventCallback>& callback) {
+    if (!event_cb_handler_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, uint32_t> WifiStaIface::getCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    uint32_t legacy_feature_set;
+    std::tie(legacy_status, legacy_feature_set) =
+        legacy_hal_.lock()->getSupportedFeatureSet(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), 0};
+    }
+    uint32_t legacy_logger_feature_set;
+    std::tie(legacy_status, legacy_logger_feature_set) =
+        legacy_hal_.lock()->getLoggerSupportedFeatureSet(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        // some devices don't support querying logger feature set
+        legacy_logger_feature_set = 0;
+    }
+    uint32_t hidl_caps;
+    if (!hidl_struct_util::convertLegacyFeaturesToHidlStaCapabilities(
+            legacy_feature_set, legacy_logger_feature_set, &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), 0};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, StaApfPacketFilterCapabilities>
+WifiStaIface::getApfPacketFilterCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::PacketFilterCapabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) =
+        legacy_hal_.lock()->getPacketFilterCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    StaApfPacketFilterCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyApfCapabilitiesToHidl(legacy_caps,
+                                                              &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiStaIface::installApfPacketFilterInternal(
+    uint32_t /* cmd_id */, const std::vector<uint8_t>& program) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setPacketFilter(ifname_, program);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, StaBackgroundScanCapabilities>
+WifiStaIface::getBackgroundScanCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_gscan_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) =
+        legacy_hal_.lock()->getGscanCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    StaBackgroundScanCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyGscanCapabilitiesToHidl(legacy_caps,
+                                                                &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+WifiStaIface::getValidFrequenciesForBandInternal(WifiBand band) {
+    static_assert(sizeof(WifiChannelInMhz) == sizeof(uint32_t),
+                  "Size mismatch");
+    legacy_hal::wifi_error legacy_status;
+    std::vector<uint32_t> valid_frequencies;
+    std::tie(legacy_status, valid_frequencies) =
+        legacy_hal_.lock()->getValidFrequenciesForBand(
+            ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
+    return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
+}
+
+WifiStatus WifiStaIface::startBackgroundScanInternal(
+    uint32_t cmd_id, const StaBackgroundScanParameters& params) {
+    legacy_hal::wifi_scan_cmd_params legacy_params;
+    if (!hidl_struct_util::convertHidlGscanParamsToLegacy(params,
+                                                          &legacy_params)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    android::wp<WifiStaIface> weak_ptr_this(this);
+    const auto& on_failure_callback =
+        [weak_ptr_this](legacy_hal::wifi_request_id id) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onBackgroundScanFailure(id).isOk()) {
+                    LOG(ERROR)
+                        << "Failed to invoke onBackgroundScanFailure callback";
+                }
+            }
+        };
+    const auto& on_results_callback =
+        [weak_ptr_this](
+            legacy_hal::wifi_request_id id,
+            const std::vector<legacy_hal::wifi_cached_scan_results>& results) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            std::vector<StaScanData> hidl_scan_datas;
+            if (!hidl_struct_util::
+                    convertLegacyVectorOfCachedGscanResultsToHidl(
+                        results, &hidl_scan_datas)) {
+                LOG(ERROR) << "Failed to convert scan results to HIDL structs";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onBackgroundScanResults(id, hidl_scan_datas)
+                         .isOk()) {
+                    LOG(ERROR)
+                        << "Failed to invoke onBackgroundScanResults callback";
+                }
+            }
+        };
+    const auto& on_full_result_callback = [weak_ptr_this](
+                                              legacy_hal::wifi_request_id id,
+                                              const legacy_hal::
+                                                  wifi_scan_result* result,
+                                              uint32_t buckets_scanned) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        StaScanResult hidl_scan_result;
+        if (!hidl_struct_util::convertLegacyGscanResultToHidl(
+                *result, true, &hidl_scan_result)) {
+            LOG(ERROR) << "Failed to convert full scan results to HIDL structs";
+            return;
+        }
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback
+                     ->onBackgroundFullScanResult(id, buckets_scanned,
+                                                  hidl_scan_result)
+                     .isOk()) {
+                LOG(ERROR)
+                    << "Failed to invoke onBackgroundFullScanResult callback";
+            }
+        }
+    };
+    legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->startGscan(
+        ifname_, cmd_id, legacy_params, on_failure_callback,
+        on_results_callback, on_full_result_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopBackgroundScanInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->stopGscan(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::enableLinkLayerStatsCollectionInternal(bool debug) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->enableLinkLayerStats(ifname_, debug);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::disableLinkLayerStatsCollectionInternal() {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->disableLinkLayerStats(ifname_);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, StaLinkLayerStats>
+WifiStaIface::getLinkLayerStatsInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::LinkLayerStats legacy_stats;
+    std::tie(legacy_status, legacy_stats) =
+        legacy_hal_.lock()->getLinkLayerStats(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    StaLinkLayerStats hidl_stats;
+    if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
+                                                             &hidl_stats)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_stats};
+}
+
+WifiStatus WifiStaIface::startRssiMonitoringInternal(uint32_t cmd_id,
+                                                     int32_t max_rssi,
+                                                     int32_t min_rssi) {
+    android::wp<WifiStaIface> weak_ptr_this(this);
+    const auto& on_threshold_breached_callback =
+        [weak_ptr_this](legacy_hal::wifi_request_id id,
+                        std::array<uint8_t, 6> bssid, int8_t rssi) {
+            const auto shared_ptr_this = weak_ptr_this.promote();
+            if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+                LOG(ERROR) << "Callback invoked on an invalid object";
+                return;
+            }
+            for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+                if (!callback->onRssiThresholdBreached(id, bssid, rssi)
+                         .isOk()) {
+                    LOG(ERROR)
+                        << "Failed to invoke onRssiThresholdBreached callback";
+                }
+            }
+        };
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->startRssiMonitoring(ifname_, cmd_id, max_rssi,
+                                                min_rssi,
+                                                on_threshold_breached_callback);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopRssiMonitoringInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->stopRssiMonitoring(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, StaRoamingCapabilities>
+WifiStaIface::getRoamingCapabilitiesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    legacy_hal::wifi_roaming_capabilities legacy_caps;
+    std::tie(legacy_status, legacy_caps) =
+        legacy_hal_.lock()->getRoamingCapabilities(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    StaRoamingCapabilities hidl_caps;
+    if (!hidl_struct_util::convertLegacyRoamingCapabilitiesToHidl(legacy_caps,
+                                                                  &hidl_caps)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_caps};
+}
+
+WifiStatus WifiStaIface::configureRoamingInternal(
+    const StaRoamingConfig& config) {
+    legacy_hal::wifi_roaming_config legacy_config;
+    if (!hidl_struct_util::convertHidlRoamingConfigToLegacy(config,
+                                                            &legacy_config)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->configureRoaming(ifname_, legacy_config);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::setRoamingStateInternal(StaRoamingState state) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->enableFirmwareRoaming(
+            ifname_, hidl_struct_util::convertHidlRoamingStateToLegacy(state));
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::enableNdOffloadInternal(bool enable) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->configureNdOffload(ifname_, enable);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::startSendingKeepAlivePacketsInternal(
+    uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
+    uint16_t /* ether_type */, const std::array<uint8_t, 6>& src_address,
+    const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->startSendingOffloadedPacket(
+            ifname_, cmd_id, ip_packet_data, src_address, dst_address,
+            period_in_ms);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::stopSendingKeepAlivePacketsInternal(uint32_t cmd_id) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->stopSendingOffloadedPacket(ifname_, cmd_id);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::setScanningMacOuiInternal(
+    const std::array<uint8_t, 3>& oui) {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->setScanningMacOui(ifname_, oui);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiStaIface::startDebugPacketFateMonitoringInternal() {
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->startPktFateMonitoring(ifname_);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
+WifiStaIface::getDebugTxPacketFatesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_tx_report> legacy_fates;
+    std::tie(legacy_status, legacy_fates) =
+        legacy_hal_.lock()->getTxPktFates(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    std::vector<WifiDebugTxPacketFateReport> hidl_fates;
+    if (!hidl_struct_util::convertLegacyVectorOfDebugTxPacketFateToHidl(
+            legacy_fates, &hidl_fates)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
+}
+
+std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
+WifiStaIface::getDebugRxPacketFatesInternal() {
+    legacy_hal::wifi_error legacy_status;
+    std::vector<legacy_hal::wifi_rx_report> legacy_fates;
+    std::tie(legacy_status, legacy_fates) =
+        legacy_hal_.lock()->getRxPktFates(ifname_);
+    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+        return {createWifiStatusFromLegacyError(legacy_status), {}};
+    }
+    std::vector<WifiDebugRxPacketFateReport> hidl_fates;
+    if (!hidl_struct_util::convertLegacyVectorOfDebugRxPacketFateToHidl(
+            legacy_fates, &hidl_fates)) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), hidl_fates};
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_sta_iface.h b/wifi/1.2/default/wifi_sta_iface.h
new file mode 100644
index 0000000..423365c
--- /dev/null
+++ b/wifi/1.2/default/wifi_sta_iface.h
@@ -0,0 +1,161 @@
+/*
+ * 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 WIFI_STA_IFACE_H_
+#define WIFI_STA_IFACE_H_
+
+#include <android-base/macros.h>
+#include <android/hardware/wifi/1.0/IWifiStaIface.h>
+#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
+
+#include "hidl_callback_util.h"
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+/**
+ * HIDL interface object used to control a STA Iface instance.
+ */
+class WifiStaIface : public V1_0::IWifiStaIface {
+   public:
+    WifiStaIface(const std::string& ifname,
+                 const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
+    // Refer to |WifiChip::invalidate()|.
+    void invalidate();
+    bool isValid();
+    std::set<sp<IWifiStaIfaceEventCallback>> getEventCallbacks();
+    std::string getName();
+
+    // HIDL methods exposed.
+    Return<void> getName(getName_cb hidl_status_cb) override;
+    Return<void> getType(getType_cb hidl_status_cb) override;
+    Return<void> registerEventCallback(
+        const sp<IWifiStaIfaceEventCallback>& callback,
+        registerEventCallback_cb hidl_status_cb) override;
+    Return<void> getCapabilities(getCapabilities_cb hidl_status_cb) override;
+    Return<void> getApfPacketFilterCapabilities(
+        getApfPacketFilterCapabilities_cb hidl_status_cb) override;
+    Return<void> installApfPacketFilter(
+        uint32_t cmd_id, const hidl_vec<uint8_t>& program,
+        installApfPacketFilter_cb hidl_status_cb) override;
+    Return<void> getBackgroundScanCapabilities(
+        getBackgroundScanCapabilities_cb hidl_status_cb) override;
+    Return<void> getValidFrequenciesForBand(
+        WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override;
+    Return<void> startBackgroundScan(
+        uint32_t cmd_id, const StaBackgroundScanParameters& params,
+        startBackgroundScan_cb hidl_status_cb) override;
+    Return<void> stopBackgroundScan(
+        uint32_t cmd_id, stopBackgroundScan_cb hidl_status_cb) override;
+    Return<void> enableLinkLayerStatsCollection(
+        bool debug, enableLinkLayerStatsCollection_cb hidl_status_cb) override;
+    Return<void> disableLinkLayerStatsCollection(
+        disableLinkLayerStatsCollection_cb hidl_status_cb) override;
+    Return<void> getLinkLayerStats(
+        getLinkLayerStats_cb hidl_status_cb) override;
+    Return<void> startRssiMonitoring(
+        uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
+        startRssiMonitoring_cb hidl_status_cb) override;
+    Return<void> stopRssiMonitoring(
+        uint32_t cmd_id, stopRssiMonitoring_cb hidl_status_cb) override;
+    Return<void> getRoamingCapabilities(
+        getRoamingCapabilities_cb hidl_status_cb) override;
+    Return<void> configureRoaming(const StaRoamingConfig& config,
+                                  configureRoaming_cb hidl_status_cb) override;
+    Return<void> setRoamingState(StaRoamingState state,
+                                 setRoamingState_cb hidl_status_cb) override;
+    Return<void> enableNdOffload(bool enable,
+                                 enableNdOffload_cb hidl_status_cb) override;
+    Return<void> startSendingKeepAlivePackets(
+        uint32_t cmd_id, const hidl_vec<uint8_t>& ip_packet_data,
+        uint16_t ether_type, const hidl_array<uint8_t, 6>& src_address,
+        const hidl_array<uint8_t, 6>& dst_address, uint32_t period_in_ms,
+        startSendingKeepAlivePackets_cb hidl_status_cb) override;
+    Return<void> stopSendingKeepAlivePackets(
+        uint32_t cmd_id,
+        stopSendingKeepAlivePackets_cb hidl_status_cb) override;
+    Return<void> setScanningMacOui(
+        const hidl_array<uint8_t, 3>& oui,
+        setScanningMacOui_cb hidl_status_cb) override;
+    Return<void> startDebugPacketFateMonitoring(
+        startDebugPacketFateMonitoring_cb hidl_status_cb) override;
+    Return<void> getDebugTxPacketFates(
+        getDebugTxPacketFates_cb hidl_status_cb) override;
+    Return<void> getDebugRxPacketFates(
+        getDebugRxPacketFates_cb hidl_status_cb) override;
+
+   private:
+    // Corresponding worker functions for the HIDL methods.
+    std::pair<WifiStatus, std::string> getNameInternal();
+    std::pair<WifiStatus, IfaceType> getTypeInternal();
+    WifiStatus registerEventCallbackInternal(
+        const sp<IWifiStaIfaceEventCallback>& callback);
+    std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
+    std::pair<WifiStatus, StaApfPacketFilterCapabilities>
+    getApfPacketFilterCapabilitiesInternal();
+    WifiStatus installApfPacketFilterInternal(
+        uint32_t cmd_id, const std::vector<uint8_t>& program);
+    std::pair<WifiStatus, StaBackgroundScanCapabilities>
+    getBackgroundScanCapabilitiesInternal();
+    std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
+    getValidFrequenciesForBandInternal(WifiBand band);
+    WifiStatus startBackgroundScanInternal(
+        uint32_t cmd_id, const StaBackgroundScanParameters& params);
+    WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
+    WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
+    WifiStatus disableLinkLayerStatsCollectionInternal();
+    std::pair<WifiStatus, StaLinkLayerStats> getLinkLayerStatsInternal();
+    WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
+                                           int32_t min_rssi);
+    WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
+    std::pair<WifiStatus, StaRoamingCapabilities>
+    getRoamingCapabilitiesInternal();
+    WifiStatus configureRoamingInternal(const StaRoamingConfig& config);
+    WifiStatus setRoamingStateInternal(StaRoamingState state);
+    WifiStatus enableNdOffloadInternal(bool enable);
+    WifiStatus startSendingKeepAlivePacketsInternal(
+        uint32_t cmd_id, const std::vector<uint8_t>& ip_packet_data,
+        uint16_t ether_type, const std::array<uint8_t, 6>& src_address,
+        const std::array<uint8_t, 6>& dst_address, uint32_t period_in_ms);
+    WifiStatus stopSendingKeepAlivePacketsInternal(uint32_t cmd_id);
+    WifiStatus setScanningMacOuiInternal(const std::array<uint8_t, 3>& oui);
+    WifiStatus startDebugPacketFateMonitoringInternal();
+    std::pair<WifiStatus, std::vector<WifiDebugTxPacketFateReport>>
+    getDebugTxPacketFatesInternal();
+    std::pair<WifiStatus, std::vector<WifiDebugRxPacketFateReport>>
+    getDebugRxPacketFatesInternal();
+
+    std::string ifname_;
+    std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
+    bool is_valid_;
+    hidl_callback_util::HidlCallbackHandler<IWifiStaIfaceEventCallback>
+        event_cb_handler_;
+
+    DISALLOW_COPY_AND_ASSIGN(WifiStaIface);
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_STA_IFACE_H_
diff --git a/wifi/1.2/default/wifi_status_util.cpp b/wifi/1.2/default/wifi_status_util.cpp
new file mode 100644
index 0000000..dd37b6b
--- /dev/null
+++ b/wifi/1.2/default/wifi_status_util.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#include "wifi_status_util.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+
+std::string legacyErrorToString(legacy_hal::wifi_error error) {
+    switch (error) {
+        case legacy_hal::WIFI_SUCCESS:
+            return "SUCCESS";
+        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+            return "UNINITIALIZED";
+        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+            return "NOT_AVAILABLE";
+        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+            return "NOT_SUPPORTED";
+        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+            return "INVALID_ARGS";
+        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+            return "INVALID_REQUEST_ID";
+        case legacy_hal::WIFI_ERROR_TIMED_OUT:
+            return "TIMED_OUT";
+        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+            return "TOO_MANY_REQUESTS";
+        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+            return "OUT_OF_MEMORY";
+        case legacy_hal::WIFI_ERROR_BUSY:
+            return "BUSY";
+        case legacy_hal::WIFI_ERROR_UNKNOWN:
+            return "UNKNOWN";
+    }
+}
+
+WifiStatus createWifiStatus(WifiStatusCode code,
+                            const std::string& description) {
+    return {code, description};
+}
+
+WifiStatus createWifiStatus(WifiStatusCode code) {
+    return createWifiStatus(code, "");
+}
+
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
+                                           const std::string& desc) {
+    switch (error) {
+        case legacy_hal::WIFI_ERROR_UNINITIALIZED:
+        case legacy_hal::WIFI_ERROR_NOT_AVAILABLE:
+            return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE, desc);
+
+        case legacy_hal::WIFI_ERROR_NOT_SUPPORTED:
+            return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED, desc);
+
+        case legacy_hal::WIFI_ERROR_INVALID_ARGS:
+        case legacy_hal::WIFI_ERROR_INVALID_REQUEST_ID:
+            return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS, desc);
+
+        case legacy_hal::WIFI_ERROR_TIMED_OUT:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+                                    desc + ", timed out");
+
+        case legacy_hal::WIFI_ERROR_TOO_MANY_REQUESTS:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+                                    desc + ", too many requests");
+
+        case legacy_hal::WIFI_ERROR_OUT_OF_MEMORY:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN,
+                                    desc + ", out of memory");
+
+        case legacy_hal::WIFI_ERROR_BUSY:
+            return createWifiStatus(WifiStatusCode::ERROR_BUSY);
+
+        case legacy_hal::WIFI_ERROR_NONE:
+            return createWifiStatus(WifiStatusCode::SUCCESS, desc);
+
+        case legacy_hal::WIFI_ERROR_UNKNOWN:
+            return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN, "unknown");
+    }
+}
+
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error) {
+    return createWifiStatusFromLegacyError(error, "");
+}
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/wifi_status_util.h b/wifi/1.2/default/wifi_status_util.h
new file mode 100644
index 0000000..e9136b3
--- /dev/null
+++ b/wifi/1.2/default/wifi_status_util.h
@@ -0,0 +1,45 @@
+/*
+ * 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 WIFI_STATUS_UTIL_H_
+#define WIFI_STATUS_UTIL_H_
+
+#include <android/hardware/wifi/1.0/IWifi.h>
+
+#include "wifi_legacy_hal.h"
+
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_2 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+std::string legacyErrorToString(legacy_hal::wifi_error error);
+WifiStatus createWifiStatus(WifiStatusCode code,
+                            const std::string& description);
+WifiStatus createWifiStatus(WifiStatusCode code);
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error,
+                                           const std::string& description);
+WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
+
+#endif  // WIFI_STATUS_UTIL_H_
diff --git a/wifi/1.2/types.hal b/wifi/1.2/types.hal
new file mode 100644
index 0000000..1636ae8
--- /dev/null
+++ b/wifi/1.2/types.hal
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::MacAddress;
+import @1.0::NanDataPathConfirmInd;
+import @1.0::WifiChannelInMhz;
+
+/**
+ * NAN configuration request parameters added in the 1.2 HAL. These are supplemental to previous
+ * versions.
+ */
+struct NanConfigRequestSupplemental {
+    /**
+     * Specify the Discovery Beacon interval in ms. Specification only applicable if the device
+     * transmits Discovery Beacons (based on the Wi-Fi Aware protocol selection criteria). The value
+     * can be increased to reduce power consumption (on devices which would transmit Discovery
+     * Beacons), however - cluster synchronization time will likely increase.
+     * Values are:
+     *  - A value of 0 indicates that the HAL sets the interval to a default (implementation specific)
+     *  - A positive value
+     */
+    uint32_t discoveryBeaconIntervalMs;
+    /**
+     * The number of spatial streams to be used for transmitting NAN management frames (does NOT apply
+     * to data-path packets). A small value may reduce power consumption for small discovery packets.
+     * Values are:
+     *  - A value of 0 indicates that the HAL sets the number to a default (implementation specific)
+     *  - A positive value
+     */
+    uint32_t numberOfSpatialStreamsInDiscovery;
+    /**
+     * Controls whether the device may terminate listening on a Discovery Window (DW) earlier than the
+     * DW termination (16ms) if no information is received. Enabling the feature will result in
+     * lower power consumption, but may result in some missed messages and hence increased latency.
+     */
+    bool enableDiscoveryWindowEarlyTermination;
+    /**
+     * Controls whether NAN RTT (ranging) is permitted. Global flag on any NAN RTT operations are
+     * allowed. Controls ranging in the context of discovery as well as direct RTT.
+     */
+    bool enableRanging;
+};
+
+/**
+ * NAN data path channel information provided to the framework.
+ */
+struct NanDataPathChannelInfo {
+    /**
+     * Channel frequency in MHz.
+     */
+    WifiChannelInMhz channelFreq;
+    /**
+     * Channel bandwidth in MHz.
+     */
+    uint32_t channelBandwidth;
+    /**
+     * Number of spatial streams used in the channel.
+     */
+    uint32_t numSpatialStreams;
+};
+
+/**
+ * NAN Data path confirmation Indication structure.
+ * Event indication is received on both initiator and responder side when negotiation for a
+ * data-path finish: on success or failure.
+ */
+struct NanDataPathConfirmInd {
+    /**
+     * Baseline information as defined in HAL 1.0.
+     */
+    @1.0::NanDataPathConfirmInd V1_0;
+    /**
+     * The channel(s) on which the NDP is scheduled to operate.
+     * Updates to the operational channels are provided using the |eventDataPathScheduleUpdate|
+     * event.
+     */
+    vec<NanDataPathChannelInfo> channelInfo;
+};
+
+/**
+ * NAN data path channel information update indication structure.
+ * Event indication is received by all NDP owners whenever the channels on which the NDP operates
+ * are updated.
+ * Note: multiple NDPs may share the same schedule, the indication specifies all NDPs to which it
+ * applies.
+ */
+struct NanDataPathScheduleUpdateInd {
+    /**
+     * The discovery address (NMI) of the peer to which the NDP is connected.
+     */
+    MacAddress peerDiscoveryAddress;
+    /**
+     * The updated channel(s) information.
+     */
+    vec<NanDataPathChannelInfo> channelInfo;
+    /**
+     * The list of NDPs to which this update applies.
+     */
+    vec<uint32_t> ndpInstanceIds;
+};
diff --git a/wifi/hostapd/1.0/Android.bp b/wifi/hostapd/1.0/Android.bp
new file mode 100644
index 0000000..a17e153
--- /dev/null
+++ b/wifi/hostapd/1.0/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi.hostapd@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IHostapd.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "HostapdStatus",
+        "HostapdStatusCode",
+    ],
+    gen_java: true,
+}
+
diff --git a/wifi/hostapd/1.0/IHostapd.hal b/wifi/hostapd/1.0/IHostapd.hal
new file mode 100644
index 0000000..3493398
--- /dev/null
+++ b/wifi/hostapd/1.0/IHostapd.hal
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.0;
+
+import android.hardware.wifi.supplicant@1.0::Ssid;
+
+/**
+ * Top-level object for managing SoftAPs.
+ */
+interface IHostapd {
+    /**
+     * Size limits for some of the params used in this interface.
+     */
+    enum ParamSizeLimits : uint32_t {
+        /** Max length of SSID param. */
+        SSID_MAX_LEN_IN_BYTES = 32,
+
+        /** Min length of PSK passphrase param. */
+        WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES = 8,
+
+        /** Max length of PSK passphrase param. */
+        WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES = 63,
+    };
+
+    /** Possble Security types. */
+    enum EncryptionType : uint32_t {
+        NONE,
+        WPA,
+        WPA2
+    };
+
+    /**
+     * Band to use for the SoftAp operations.
+     * When using ACS, special value |BAND_ANY| can be
+     * used to indicate that any supported band can be used. This special
+     * case is currently supported only with drivers with which
+     * offloaded ACS is used.
+     */
+    enum Band : uint32_t {
+        BAND_2_4_GHZ,
+        BAND_5_GHZ,
+        BAND_ANY
+    };
+
+    /**
+     * Parameters to control the HW mode for the interface.
+     */
+    struct HwModeParams {
+        /**
+         * Whether IEEE 802.11n (HT) is enabled or not.
+         * Note: hwMode=G (2.4 GHz) and hwMode=A (5 GHz) is used to specify
+         * the band.
+         */
+        bool enable80211N;
+         /**
+          * Whether IEEE 802.11ac (VHT) is enabled or not.
+          * Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
+          */
+        bool enable80211AC;
+    };
+
+    /**
+     * Parameters to control the channel selection for the interface.
+     */
+    struct ChannelParams {
+        /**
+         * Whether to enable ACS (Automatic Channel Selection) or not.
+         * The channel can be selected automatically at run time by setting
+         * this flag, which must enable the ACS survey based algorithm.
+         */
+        bool enableAcs;
+        /**
+         * This option can be used to exclude all DFS channels from the ACS
+         * channel list in cases where the driver supports DFS channels.
+         **/
+        bool acsShouldExcludeDfs;
+        /**
+         * Channel number (IEEE 802.11) to use for the interface.
+         * If ACS is enabled, this field is ignored.
+         */
+        uint32_t channel;
+        /**
+         * Band to use for the SoftAp operations.
+         */
+        Band band;
+    };
+
+    /**
+     * Parameters to use for setting up the access point interface.
+     */
+    struct IfaceParams {
+        /** Name of the interface */
+        string ifaceName;
+        /** Hw mode params for the interface */
+        HwModeParams hwModeParams;
+        /** Chanel params for the interface */
+        ChannelParams channelParams;
+    };
+
+    /**
+     * Parameters to use for setting up the access point network.
+     */
+    struct NetworkParams {
+        /** SSID to set for the network */
+        Ssid ssid;
+        /** Whether the network needs to be hidden or not. */
+        bool isHidden;
+        /** Key management mask for the network. */
+        EncryptionType encryptionType;
+        /** Passphrase for WPA_PSK network. */
+        string pskPassphrase;
+    };
+
+    /**
+     * Adds a new access point for hostapd to control.
+     *
+     * This should trigger the setup of an access point with the specified
+     * interface and network params.
+     *
+     * @param ifaceParams AccessPoint Params for the access point.
+     * @param nwParams Network Params for the access point.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |HostapdStatusCode.SUCCESS|,
+     *         |HostapdStatusCode.FAILURE_ARGS_INVALID|,
+     *         |HostapdStatusCode.FAILURE_UNKNOWN|,
+     *         |HostapdStatusCode.FAILURE_IFACE_EXISTS|
+     */
+    addAccessPoint(IfaceParams ifaceParams, NetworkParams nwParams)
+        generates(HostapdStatus status);
+
+    /**
+     * Removes an existing access point from hostapd.
+     *
+     * This should bring down the access point previously setup on the
+     * interface.
+     *
+     * @param ifaceName Name of the interface.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |HostapdStatusCode.SUCCESS|,
+     *         |HostapdStatusCode.FAILURE_UNKNOWN|,
+     *         |HostapdStatusCode.FAILURE_IFACE_UNKNOWN|
+     */
+    removeAccessPoint(string ifaceName) generates(HostapdStatus status);
+
+    /**
+     * Terminate the service.
+     * This must de-register the service and clear all state. If this HAL
+     * supports the lazy HAL protocol, then this may trigger daemon to exit and
+     * wait to be restarted.
+     */
+    oneway terminate();
+};
diff --git a/wifi/hostapd/1.0/types.hal b/wifi/hostapd/1.0/types.hal
new file mode 100644
index 0000000..31bbc34
--- /dev/null
+++ b/wifi/hostapd/1.0/types.hal
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.0;
+/**
+ * Enum values indicating the status of any hostapd operation.
+ */
+enum HostapdStatusCode : uint32_t {
+  /** No errors. */
+  SUCCESS,
+  /** Unknown failure occured. */
+  FAILURE_UNKNOWN,
+  /** One or more of the incoming args is invalid. */
+  FAILURE_ARGS_INVALID,
+  /** Iface with the provided name does not exist. */
+  FAILURE_IFACE_UNKNOWN,
+  /** Iface with the provided name already exists. */
+  FAILURE_IFACE_EXISTS
+};
+
+/**
+ * Generic structure to return the status of any hostapd operation.
+ */
+struct HostapdStatus {
+  HostapdStatusCode code;
+  /**
+   * A vendor-specific error message to provide more information beyond the
+   * status code.
+   * This must be used for debugging purposes only.
+   */
+  string debugMessage;
+};
diff --git a/wifi/hostapd/1.0/vts/functional/Android.bp b/wifi/hostapd/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..7a920b4
--- /dev/null
+++ b/wifi/hostapd/1.0/vts/functional/Android.bp
@@ -0,0 +1,52 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "VtsHalWifiHostapdV1_0TargetTestUtil",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["hostapd_hidl_test_utils.cpp"],
+    export_include_dirs: [
+        "."
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi.hostapd@1.0",
+        "android.hardware.wifi@1.0",
+        "libcrypto",
+        "libgmock",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+}
+
+cc_test {
+    name: "VtsHalWifiHostapdV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalWifiHostapdV1_0TargetTest.cpp",
+        "hostapd_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiHostapdV1_0TargetTestUtil",
+        "android.hardware.wifi.hostapd@1.0",
+        "android.hardware.wifi@1.0",
+        "libcrypto",
+        "libgmock",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+}
diff --git a/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp b/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp
new file mode 100644
index 0000000..64e6fbe
--- /dev/null
+++ b/wifi/hostapd/1.0/vts/functional/VtsHalWifiHostapdV1_0TargetTest.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "hostapd_hidl_test_utils.h"
+
+class HostapdHidlEnvironment : public ::testing::Environment {
+   public:
+    virtual void SetUp() override { stopHostapd(); }
+    virtual void TearDown() override { startHostapdAndWaitForHidlService(); }
+};
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(new HostapdHidlEnvironment);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_call_util.h b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_call_util.h
new file mode 100644
index 0000000..2f71ccb
--- /dev/null
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_call_util.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file is copied from
+// hardware/interfaces/wifi/1.0/vts/functional/wifi_hidl_call_util.h
+// Please make sure these two file are consistent.
+
+#pragma once
+
+#include <functional>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace {
+namespace detail {
+template <typename>
+struct functionArgSaver;
+
+// Provides a std::function that takes one argument, and a buffer
+// wherein the function will store its argument. The buffer has
+// the same type as the argument, but with const and reference
+// modifiers removed.
+template <typename ArgT>
+struct functionArgSaver<std::function<void(ArgT)>> final {
+    using StorageT = typename std::remove_const<
+        typename std::remove_reference<ArgT>::type>::type;
+
+    std::function<void(ArgT)> saveArgs = [this](ArgT arg) {
+        this->saved_values = arg;
+    };
+
+    StorageT saved_values;
+};
+
+// Provides a std::function that takes two arguments, and a buffer
+// wherein the function will store its arguments. The buffer is a
+// std::pair, whose elements have the same types as the arguments
+// (but with const and reference modifiers removed).
+template <typename Arg1T, typename Arg2T>
+struct functionArgSaver<std::function<void(Arg1T, Arg2T)>> final {
+    using StorageT =
+        std::pair<typename std::remove_const<
+                      typename std::remove_reference<Arg1T>::type>::type,
+                  typename std::remove_const<
+                      typename std::remove_reference<Arg2T>::type>::type>;
+
+    std::function<void(Arg1T, Arg2T)> saveArgs = [this](Arg1T arg1,
+                                                        Arg2T arg2) {
+        this->saved_values = {arg1, arg2};
+    };
+
+    StorageT saved_values;
+};
+
+// Provides a std::function that takes three or more arguments, and a
+// buffer wherein the function will store its arguments. The buffer is a
+// std::tuple whose elements have the same types as the arguments (but
+// with const and reference modifiers removed).
+template <typename... ArgT>
+struct functionArgSaver<std::function<void(ArgT...)>> final {
+    using StorageT = std::tuple<typename std::remove_const<
+        typename std::remove_reference<ArgT>::type>::type...>;
+
+    std::function<void(ArgT...)> saveArgs = [this](ArgT... arg) {
+        this->saved_values = {arg...};
+    };
+
+    StorageT saved_values;
+};
+
+// Invokes |method| on |object|, providing |method| a CallbackT as the
+// final argument. Returns a copy of the parameters that |method| provided
+// to CallbackT. (The parameters are returned by value.)
+template <typename CallbackT, typename MethodT, typename ObjectT,
+          typename... ArgT>
+typename functionArgSaver<CallbackT>::StorageT invokeMethod(
+    MethodT method, ObjectT object, ArgT&&... methodArg) {
+    functionArgSaver<CallbackT> result_buffer;
+    const auto& res = ((*object).*method)(std::forward<ArgT>(methodArg)...,
+                                          result_buffer.saveArgs);
+    EXPECT_TRUE(res.isOk());
+    return result_buffer.saved_values;
+}
+}  // namespace detail
+}  // namespace
+
+// Invokes |method| on |strong_pointer|, passing provided arguments through to
+// |method|.
+//
+// Returns either:
+// - A copy of the result callback parameter (for callbacks with a single
+//   parameter), OR
+// - A pair containing a copy of the result callback parameters (for callbacks
+//   with two parameters), OR
+// - A tuple containing a copy of the result callback paramters (for callbacks
+//   with three or more parameters).
+//
+// Example usage:
+//   EXPECT_EQ(HostapdStatusCode::SUCCESS,
+//       HIDL_INVOKE(strong_pointer, methodReturningHostapdStatus).code);
+//   EXPECT_EQ(HostapdStatusCode::SUCCESS,
+//       HIDL_INVOKE(strong_pointer, methodReturningHostapdStatusAndOneMore)
+//         .first.code);
+//   EXPECT_EQ(HostapdStatusCode::SUCCESS, std::get<0>(
+//       HIDL_INVOKE(strong_pointer, methodReturningHostapdStatusAndTwoMore))
+//         .code);
+#define HIDL_INVOKE(strong_pointer, method, ...)                              \
+    (detail::invokeMethod<                                                    \
+        std::remove_reference<decltype(*strong_pointer)>::type::method##_cb>( \
+        &std::remove_reference<decltype(*strong_pointer)>::type::method,      \
+        strong_pointer, ##__VA_ARGS__))
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp
new file mode 100644
index 0000000..5f51cfb
--- /dev/null
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp
@@ -0,0 +1,222 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
+
+#include "hostapd_hidl_call_util.h"
+#include "hostapd_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::wifi::hostapd::V1_0::IHostapd;
+using ::android::hardware::wifi::hostapd::V1_0::HostapdStatus;
+using ::android::hardware::wifi::hostapd::V1_0::HostapdStatusCode;
+
+namespace {
+constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1',
+                                     '2', '3', '4', '5'};
+constexpr char kNwPassphrase[] = "test12345";
+constexpr int kIfaceChannel = 6;
+constexpr int kIfaceInvalidChannel = 567;
+}  // namespace
+
+class HostapdHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        startHostapdAndWaitForHidlService();
+        hostapd_ = getHostapd();
+        ASSERT_NE(hostapd_.get(), nullptr);
+    }
+
+    virtual void TearDown() override { stopHostapd(); }
+
+   protected:
+    std::string getPrimaryWlanIfaceName() {
+        std::array<char, PROPERTY_VALUE_MAX> buffer;
+        property_get("wifi.interface", buffer.data(), "wlan0");
+        return buffer.data();
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithAcs() {
+        IHostapd::IfaceParams iface_params;
+        iface_params.ifaceName = getPrimaryWlanIfaceName();
+        iface_params.hwModeParams.enable80211N = true;
+        iface_params.hwModeParams.enable80211AC = false;
+        iface_params.channelParams.enableAcs = true;
+        iface_params.channelParams.acsShouldExcludeDfs = true;
+        iface_params.channelParams.channel = 0;
+        iface_params.channelParams.band = IHostapd::Band::BAND_ANY;
+        return iface_params;
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithoutAcs() {
+        IHostapd::IfaceParams iface_params;
+        iface_params.ifaceName = getPrimaryWlanIfaceName();
+        iface_params.hwModeParams.enable80211N = true;
+        iface_params.hwModeParams.enable80211AC = false;
+        iface_params.channelParams.enableAcs = false;
+        iface_params.channelParams.acsShouldExcludeDfs = false;
+        iface_params.channelParams.channel = kIfaceChannel;
+        iface_params.channelParams.band = IHostapd::Band::BAND_2_4_GHZ;
+        return iface_params;
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() {
+        IHostapd::IfaceParams iface_params;
+        iface_params.ifaceName = getPrimaryWlanIfaceName();
+        iface_params.hwModeParams.enable80211N = true;
+        iface_params.hwModeParams.enable80211AC = false;
+        iface_params.channelParams.enableAcs = false;
+        iface_params.channelParams.acsShouldExcludeDfs = false;
+        iface_params.channelParams.channel = kIfaceInvalidChannel;
+        iface_params.channelParams.band = IHostapd::Band::BAND_2_4_GHZ;
+        return iface_params;
+    }
+
+    IHostapd::NetworkParams getPskNwParams() {
+        IHostapd::NetworkParams nw_params;
+        nw_params.ssid =
+            std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+        nw_params.isHidden = false;
+        nw_params.encryptionType = IHostapd::EncryptionType::WPA2;
+        nw_params.pskPassphrase = kNwPassphrase;
+        return nw_params;
+    }
+
+    IHostapd::NetworkParams getInvalidPskNwParams() {
+        IHostapd::NetworkParams nw_params;
+        nw_params.ssid =
+            std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+        nw_params.isHidden = false;
+        nw_params.encryptionType = IHostapd::EncryptionType::WPA2;
+        return nw_params;
+    }
+
+    IHostapd::NetworkParams getOpenNwParams() {
+        IHostapd::NetworkParams nw_params;
+        nw_params.ssid =
+            std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+        nw_params.isHidden = false;
+        nw_params.encryptionType = IHostapd::EncryptionType::NONE;
+        return nw_params;
+    }
+    // IHostapd object used for all tests in this fixture.
+    sp<IHostapd> hostapd_;
+};
+
+/*
+ * Create:
+ * Ensures that an instance of the IHostapd proxy object is
+ * successfully created.
+ */
+TEST(HostapdHidlTestNoFixture, Create) {
+    startHostapdAndWaitForHidlService();
+    EXPECT_NE(nullptr, getHostapd().get());
+    stopHostapd();
+}
+
+/**
+ * Adds an access point with PSK network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_F(HostapdHidlTest, AddPskAccessPointWithAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithAcs(),
+                              getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_F(HostapdHidlTest, AddOpenAccessPointWithAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithAcs(),
+                              getOpenNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_F(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint,
+                              getIfaceParamsWithoutAcs(), getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_F(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint,
+                              getIfaceParamsWithoutAcs(), getOpenNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS enabled.
+ * Access point creation & removal should pass.
+ */
+TEST_F(HostapdHidlTest, RemoveAccessPointWithAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithAcs(),
+                              getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    status =
+        HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS disabled.
+ * Access point creation & removal should pass.
+ */
+TEST_F(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint,
+                              getIfaceParamsWithoutAcs(), getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    status =
+        HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid channel.
+ * Access point creation should fail.
+ */
+TEST_F(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint,
+                    getIfaceParamsWithInvalidChannel(), getPskNwParams());
+    EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid PSK network config.
+ * Access point creation should fail.
+ */
+TEST_F(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint, getIfaceParamsWithoutAcs(),
+                    getInvalidPskNwParams());
+    EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
new file mode 100644
index 0000000..0915150
--- /dev/null
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.0/IServiceNotification.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <wifi_system/hostapd_manager.h>
+#include <wifi_system/interface_tool.h>
+
+#include "hostapd_hidl_test_utils.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::hostapd::V1_0::IHostapd;
+using ::android::hardware::wifi::hostapd::V1_0::HostapdStatus;
+using ::android::hardware::wifi::hostapd::V1_0::HostapdStatusCode;
+using ::android::hidl::manager::V1_0::IServiceNotification;
+using ::android::wifi_system::HostapdManager;
+
+namespace {
+const char kHostapdServiceName[] = "default";
+
+// Helper function to initialize the driver and firmware to AP mode
+// using the vendor HAL HIDL interface.
+void initilializeDriverAndFirmware() {
+    sp<IWifiChip> wifi_chip = getWifiChip();
+    ChipModeId mode_id;
+    EXPECT_TRUE(configureChipToSupportIfaceType(
+        wifi_chip, ::android::hardware::wifi::V1_0::IfaceType::AP, &mode_id));
+}
+
+// Helper function to deinitialize the driver and firmware
+// using the vendor HAL HIDL interface.
+void deInitilializeDriverAndFirmware() { stopWifi(); }
+}  // namespace
+
+// Utility class to wait for wpa_hostapd's HIDL service registration.
+class ServiceNotificationListener : public IServiceNotification {
+   public:
+    Return<void> onRegistration(const hidl_string& fully_qualified_name,
+                                const hidl_string& instance_name,
+                                bool pre_existing) override {
+        if (pre_existing) {
+            return Void();
+        }
+        std::unique_lock<std::mutex> lock(mutex_);
+        registered_.push_back(std::string(fully_qualified_name.c_str()) + "/" +
+                              instance_name.c_str());
+        lock.unlock();
+        condition_.notify_one();
+        return Void();
+    }
+
+    bool registerForHidlServiceNotifications(const std::string& instance_name) {
+        if (!IHostapd::registerForNotifications(instance_name, this)) {
+            return false;
+        }
+        configureRpcThreadpool(2, false);
+        return true;
+    }
+
+    bool waitForHidlService(uint32_t timeout_in_millis,
+                            const std::string& instance_name) {
+        std::unique_lock<std::mutex> lock(mutex_);
+        condition_.wait_for(lock, std::chrono::milliseconds(timeout_in_millis),
+                            [&]() { return registered_.size() >= 1; });
+        if (registered_.size() != 1) {
+            return false;
+        }
+        std::string expected_registered =
+            std::string(IHostapd::descriptor) + "/" + instance_name;
+        if (registered_[0] != expected_registered) {
+            LOG(ERROR) << "Expected: " << expected_registered
+                       << ", Got: " << registered_[0];
+            return false;
+        }
+        return true;
+    }
+
+   private:
+    std::vector<std::string> registered_{};
+    std::mutex mutex_;
+    std::condition_variable condition_;
+};
+
+void stopHostapd() {
+    HostapdManager hostapd_manager;
+
+    ASSERT_TRUE(hostapd_manager.StopHostapd());
+    deInitilializeDriverAndFirmware();
+}
+
+void startHostapdAndWaitForHidlService() {
+    initilializeDriverAndFirmware();
+
+    android::sp<ServiceNotificationListener> notification_listener =
+        new ServiceNotificationListener();
+    ASSERT_TRUE(notification_listener->registerForHidlServiceNotifications(
+        kHostapdServiceName));
+
+    HostapdManager hostapd_manager;
+    ASSERT_TRUE(hostapd_manager.StartHostapd());
+
+    ASSERT_TRUE(
+        notification_listener->waitForHidlService(200, kHostapdServiceName));
+}
+
+sp<IHostapd> getHostapd() {
+    return ::testing::VtsHalHidlTargetTestBase::getService<IHostapd>();
+}
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
new file mode 100644
index 0000000..74ed284
--- /dev/null
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HOSTAPD_HIDL_TEST_UTILS_H
+#define HOSTAPD_HIDL_TEST_UTILS_H
+
+#include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
+
+// Used to stop the android wifi framework before every test.
+void stopWifiFramework();
+void startWifiFramework();
+void stopHostapd();
+// Used to configure the chip, driver and start wpa_hostapd before every
+// test.
+void startHostapdAndWaitForHidlService();
+
+// Helper functions to obtain references to the various HIDL interface objects.
+// Note: We only have a single instance of each of these objects currently.
+// These helper functions should be modified to return vectors if we support
+// multiple instances.
+android::sp<android::hardware::wifi::hostapd::V1_0::IHostapd> getHostapd();
+
+#endif /* HOSTAPD_HIDL_TEST_UTILS_H */
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index 24b9f6f..f742ecd 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -14,19 +14,37 @@
 // limitations under the License.
 //
 
+cc_library_static {
+    name: "VtsHalWifiSupplicantV1_0TargetTestUtil",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["supplicant_hidl_test_utils.cpp"],
+    export_include_dirs: [
+        "."
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hardware.wifi@1.0",
+        "libcrypto",
+        "libgmock",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+}
+
 cc_test {
     name: "VtsHalWifiSupplicantV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "VtsHalWifiSupplicantV1_0TargetTest.cpp",
         "supplicant_hidl_test.cpp",
-        "supplicant_hidl_test_utils.cpp",
         "supplicant_p2p_iface_hidl_test.cpp",
         "supplicant_sta_iface_hidl_test.cpp",
         "supplicant_sta_network_hidl_test.cpp",
     ],
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_0TargetTestUtil",
         "android.hardware.wifi.supplicant@1.0",
         "android.hardware.wifi@1.0",
         "libcrypto",
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
index 33f3049..7fa20c9 100644
--- a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantV1_0TargetTest.cpp
@@ -25,8 +25,7 @@
     virtual void SetUp() override {
         stopSupplicant();
     }
-    virtual void TearDown() override {
-    }
+    virtual void TearDown() override { startSupplicantAndWaitForHidlService(); }
 };
 
 int main(int argc, char** argv) {
diff --git a/wifi/supplicant/1.1/Android.bp b/wifi/supplicant/1.1/Android.bp
new file mode 100644
index 0000000..fafd6ad
--- /dev/null
+++ b/wifi/supplicant/1.1/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi.supplicant@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "ISupplicant.hal",
+        "ISupplicantStaNetwork.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
+
diff --git a/wifi/supplicant/1.1/ISupplicant.hal b/wifi/supplicant/1.1/ISupplicant.hal
new file mode 100644
index 0000000..f3ec0fc
--- /dev/null
+++ b/wifi/supplicant/1.1/ISupplicant.hal
@@ -0,0 +1,65 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi.supplicant@1.1;
+
+import @1.0::ISupplicant;
+import @1.0::ISupplicantIface;
+import @1.0::SupplicantStatus;
+
+/**
+ * Interface exposed by the supplicant HIDL service registered
+ * with the hardware service manager.
+ * This is the root level object for any the supplicant interactions.
+ */
+interface ISupplicant extends @1.0::ISupplicant {
+    /**
+     * Registers a wireless interface in supplicant.
+     *
+     * @param ifaceInfo Combination of the interface type and name(e.g wlan0).
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_EXISTS|
+     * @return iface HIDL interface object representing the interface if
+     *         successful, null otherwise.
+     */
+    addInterface(IfaceInfo ifaceInfo)
+        generates (SupplicantStatus status, ISupplicantIface iface);
+
+    /**
+     * Deregisters a wireless interface from supplicant.
+     *
+     * @param ifaceInfo Combination of the interface type and name(e.g wlan0).
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_IFACE_UNKOWN|
+     */
+    removeInterface(IfaceInfo ifaceInfo) generates (SupplicantStatus status);
+
+    /**
+     * Terminate the service.
+     * This must de-register the service and clear all state. If this HAL
+     * supports the lazy HAL protocol, then this may trigger daemon to exit and
+     * wait to be restarted.
+     */
+    oneway terminate();
+};
diff --git a/wifi/supplicant/1.1/ISupplicantStaNetwork.hal b/wifi/supplicant/1.1/ISupplicantStaNetwork.hal
new file mode 100644
index 0000000..186fe75
--- /dev/null
+++ b/wifi/supplicant/1.1/ISupplicantStaNetwork.hal
@@ -0,0 +1,100 @@
+/*
+ * Copyright 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.
+ */
+
+package android.hardware.wifi.supplicant@1.1;
+
+import @1.0::ISupplicantNetwork;
+import @1.0::ISupplicantStaNetworkCallback;
+import @1.0::SupplicantStatus;
+import @1.0::ISupplicantStaNetwork;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * configuration it controls.
+ */
+interface ISupplicantStaNetwork extends @1.0::ISupplicantStaNetwork {
+    /**
+     * EAP IMSI Identity to be used for authentication to EAP SIM networks.
+     * The identity must be derived from the IMSI retrieved from the SIM card.
+     *
+     * See RFC4186 & RFC4187 & RFC5448 for EAP SIM protocols.
+     *
+     * Identity string is built from IMSI. Format is:
+     *       eapPrefix | IMSI | '@' | realm
+     * where:
+     * - "|" denotes concatenation
+     * - realm is the 3GPP network domain name derived from the given
+     *   MCC/MNC according to the 3GGP spec(TS23.003)
+     *
+     * eapPrefix value:
+     * '0' - EAP-AKA Identity
+     * '1' - EAP-SIM Identity
+     * '6' - EAP-AKA-PRIME Identity
+     */
+    typedef vec<uint8_t> EapSimIdentity;
+
+    /**
+     * Encrypted EAP IMSI Identity to be used for authentication to EAP SIM
+     * networks which supports encrypted IMSI.
+     * The identity must be derived from the IMSI retrieved from the SIM card.
+     * This identity is then encrypted using the public key of the carrier.
+     *
+     * See RFC4186 & RFC4187 & RFC5448 for EAP SIM protocols.
+     * See section 7.1 of RFC 2437 for RSA-OAEP encryption scheme.
+     *
+     * Identity string is built from encrypted IMSI. Format is:
+     *       '\0' | Base64{RSA-OAEP-SHA-256(eapPrefix | IMSI)}
+     *       | '@' | realm | {',' Key Identifier}
+     * where:
+     * - "|" denotes concatenation
+     * - "{}" denotes an optional value
+     * - realm is the 3GPP network domain name derived from the given
+     *   MCC/MNC according to the 3GGP spec(TS23.003)
+     * - Key Identifier is a null-terminated string of the form "<Key>=<Value>"
+     */
+    typedef vec<uint8_t> EapSimEncryptedIdentity;
+
+    /**
+     * Set EAP encrypted IMSI Identity for this network.
+     *
+     * @param identity Identity string built from the encrypted IMSI.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    setEapEncryptedImsiIdentity(EapSimEncryptedIdentity identity)
+        generates (SupplicantStatus status);
+
+    /**
+     * Used to send a response to the
+     * |ISupplicantNetworkCallback.onNetworkEapIdentityRequest| request.
+     *
+     * @param identity Identity string containing the IMSI.
+     * @param encryptedIdentity Identity string containing the encrypted IMSI.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+     */
+    sendNetworkEapIdentityResponse_1_1(
+            EapSimIdentity identity,
+            EapSimEncryptedIdentity encryptedIdentity)
+        generates (SupplicantStatus status);
+};
diff --git a/wifi/supplicant/1.1/vts/Android.mk b/wifi/supplicant/1.1/vts/Android.mk
new file mode 100644
index 0000000..6361f9b
--- /dev/null
+++ b/wifi/supplicant/1.1/vts/Android.mk
@@ -0,0 +1,2 @@
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/wifi/supplicant/1.1/vts/functional/Android.bp b/wifi/supplicant/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..9375cf5
--- /dev/null
+++ b/wifi/supplicant/1.1/vts/functional/Android.bp
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "VtsHalWifiSupplicantV1_1TargetTestUtil",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["supplicant_hidl_test_utils_1_1.cpp"],
+    export_include_dirs: [
+        "."
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hardware.wifi.supplicant@1.1",
+        "android.hardware.wifi@1.0",
+        "libcrypto",
+        "libgmock",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+}
+
+cc_test {
+    name: "VtsHalWifiSupplicantV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalWifiSupplicantV1_1TargetTest.cpp",
+        "supplicant_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_0TargetTestUtil",
+        "VtsHalWifiSupplicantV1_1TargetTestUtil",
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hardware.wifi.supplicant@1.1",
+        "android.hardware.wifi@1.0",
+        "libcrypto",
+        "libgmock",
+        "libwifi-system",
+        "libwifi-system-iface",
+    ],
+}
diff --git a/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
new file mode 100644
index 0000000..b5e369a
--- /dev/null
+++ b/wifi/supplicant/1.1/vts/functional/VtsHalWifiSupplicantV1_1TargetTest.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "supplicant_hidl_test_utils.h"
+
+class SupplicantHidlEnvironment : public ::testing::Environment {
+   public:
+    virtual void SetUp() override { stopSupplicant(); }
+    virtual void TearDown() override { startSupplicantAndWaitForHidlService(); }
+};
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(new SupplicantHidlEnvironment);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
new file mode 100644
index 0000000..c29fd0a
--- /dev/null
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <cutils/properties.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <android/hardware/wifi/supplicant/1.0/types.h>
+#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_1.h"
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::wifi::supplicant::V1_0::ISupplicantIface;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicant;
+using ::android::sp;
+
+class SupplicantHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        startSupplicantAndWaitForHidlService();
+        supplicant_ = getSupplicant_1_1();
+        ASSERT_NE(supplicant_.get(), nullptr);
+    }
+
+    virtual void TearDown() override { stopSupplicant(); }
+
+   protected:
+    // ISupplicant object used for all tests in this fixture.
+    sp<ISupplicant> supplicant_;
+
+    std::string getWlan0IfaceName() {
+        std::array<char, PROPERTY_VALUE_MAX> buffer;
+        property_get("wifi.interface", buffer.data(), "wlan0");
+        return buffer.data();
+    }
+
+    std::string getP2pIfaceName() {
+        std::array<char, PROPERTY_VALUE_MAX> buffer;
+        property_get("wifi.direct.interface", buffer.data(), "p2p0");
+        return buffer.data();
+    }
+};
+
+/*
+ * AddStaInterface
+ */
+TEST_F(SupplicantHidlTest, AddStaInterface) {
+    ISupplicant::IfaceInfo iface_info;
+    iface_info.name = getWlan0IfaceName();
+    iface_info.type = IfaceType::STA;
+    supplicant_->addInterface(
+        iface_info,
+        [&](const SupplicantStatus& status, const sp<ISupplicantIface>& iface) {
+            EXPECT_TRUE(
+                (status.code == SupplicantStatusCode::SUCCESS) ||
+                (status.code == SupplicantStatusCode::FAILURE_IFACE_EXISTS));
+            EXPECT_NE(nullptr, iface.get());
+        });
+}
+
+/*
+ * AddP2pInterface
+ */
+TEST_F(SupplicantHidlTest, AddP2pInterface) {
+    ISupplicant::IfaceInfo iface_info;
+    iface_info.name = getP2pIfaceName();
+    iface_info.type = IfaceType::P2P;
+    supplicant_->addInterface(
+        iface_info,
+        [&](const SupplicantStatus& status, const sp<ISupplicantIface>& iface) {
+            EXPECT_TRUE(
+                (status.code == SupplicantStatusCode::SUCCESS) ||
+                (status.code == SupplicantStatusCode::FAILURE_IFACE_EXISTS));
+            EXPECT_NE(nullptr, iface.get());
+        });
+}
+
+/*
+ * RemoveStaInterface
+ */
+TEST_F(SupplicantHidlTest, RemoveStaInterface) {
+    ISupplicant::IfaceInfo iface_info;
+    iface_info.name = getWlan0IfaceName();
+    iface_info.type = IfaceType::STA;
+
+    supplicant_->addInterface(
+        iface_info,
+        [&](const SupplicantStatus& status, const sp<ISupplicantIface>& iface) {
+            EXPECT_TRUE(
+                (status.code == SupplicantStatusCode::SUCCESS) ||
+                (status.code == SupplicantStatusCode::FAILURE_IFACE_EXISTS));
+            EXPECT_NE(nullptr, iface.get());
+        });
+    supplicant_->removeInterface(
+        iface_info, [&](const SupplicantStatus& status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
+
+/*
+ * RemoveP2pInterface
+ */
+TEST_F(SupplicantHidlTest, RemoveP2pInterface) {
+    ISupplicant::IfaceInfo iface_info;
+    iface_info.name = getP2pIfaceName();
+    iface_info.type = IfaceType::P2P;
+
+    supplicant_->addInterface(
+        iface_info,
+        [&](const SupplicantStatus& status, const sp<ISupplicantIface>& iface) {
+            EXPECT_TRUE(
+                (status.code == SupplicantStatusCode::SUCCESS) ||
+                (status.code == SupplicantStatusCode::FAILURE_IFACE_EXISTS));
+            EXPECT_NE(nullptr, iface.get());
+        });
+    supplicant_->removeInterface(
+        iface_info, [&](const SupplicantStatus& status) {
+            EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+        });
+}
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
new file mode 100644
index 0000000..8cc4a9f
--- /dev/null
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_1.h"
+
+using ::android::hardware::wifi::supplicant::V1_1::ISupplicant;
+using ::android::sp;
+
+sp<ISupplicant> getSupplicant_1_1() {
+    return ISupplicant::castFrom(getSupplicant());
+}
diff --git a/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
new file mode 100644
index 0000000..c42a35b
--- /dev/null
+++ b/wifi/supplicant/1.1/vts/functional/supplicant_hidl_test_utils_1_1.h
@@ -0,0 +1,25 @@
+/*
+ * 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 SUPPLICANT_HIDL_TEST_UTILS_1_1_H
+#define SUPPLICANT_HIDL_TEST_UTILS_1_1_H
+
+#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
+
+android::sp<android::hardware::wifi::supplicant::V1_1::ISupplicant>
+    getSupplicant_1_1();
+
+#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_1_H */