Merge "NNAPI VTS update in response to utility function change"
diff --git a/automotive/evs/1.1/Android.bp b/automotive/evs/1.1/Android.bp
index d2e85f1..c850c91 100644
--- a/automotive/evs/1.1/Android.bp
+++ b/automotive/evs/1.1/Android.bp
@@ -10,13 +10,15 @@
         "types.hal",
         "IEvsCamera.hal",
         "IEvsCameraStream.hal",
+        "IEvsEnumerator.hal",
     ],
     interfaces: [
         "android.hardware.automotive.evs@1.0",
+        "android.hardware.camera.device@3.2",
         "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.common@1.2",
         "android.hidl.base@1.0",
     ],
-    gen_java: true,
+    gen_java: false,
 }
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
index 21ca79e..975b6c6 100644
--- a/automotive/evs/1.1/IEvsCamera.hal
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -26,6 +26,14 @@
  */
 interface IEvsCamera extends @1.0::IEvsCamera {
     /**
+     * Returns the description of this camera.
+     *
+     * @return info The description of this camera.  This must be the same value as
+     *              reported by EvsEnumerator::getCameraList_1_1().
+     */
+    getCameraInfo_1_1() generates (CameraDesc info);
+
+    /**
      * Requests to pause EVS camera stream events.
      *
      * Like stopVideoStream(), events may continue to arrive for some time
@@ -100,7 +108,27 @@
     unsetMaster() generates (EvsResult result);
 
     /**
-     * Requests to set a camera parameter.
+     * Retrieves a list of parameters this camera supports.
+     *
+     * @return params A list of CameraParam that this camera supports.
+     */
+    getParameterList() generates (vec<CameraParam> params);
+
+    /**
+     * Requests a valid value range of a camera parameter
+     *
+     * @param  id    The identifier of camera parameter, CameraParam enum.
+     *
+     * @return min   The lower bound of valid parameter value range.
+     * @return max   The upper bound of valid parameter value range.
+     * @return step  The resolution of values in valid range.
+     */
+    getIntParameterRange(CameraParam id)
+        generates (int32_t min, int32_t max, int32_t step);
+
+    /**
+     * Requests to set a camera parameter.  Only a request from the master
+     * client will be processed successfully.
      *
      * @param  id             The identifier of camera parameter, CameraParam enum.
      *         value          A desired parameter value.
@@ -114,7 +142,7 @@
      *                        from what the client gives if, for example, the
      *                        driver does not support a target parameter.
      */
-    setParameter(CameraParam id, int32_t value)
+    setIntParameter(CameraParam id, int32_t value)
         generates (EvsResult result, int32_t effectiveValue);
 
     /**
@@ -126,5 +154,5 @@
      *                not supported.
      *         value  A value of requested camera parameter.
      */
-    getParameter(CameraParam id) generates(EvsResult result, int32_t value);
+    getIntParameter(CameraParam id) generates(EvsResult result, int32_t value);
 };
diff --git a/automotive/evs/1.1/IEvsCameraStream.hal b/automotive/evs/1.1/IEvsCameraStream.hal
index 7c7f832..9e4ea19 100644
--- a/automotive/evs/1.1/IEvsCameraStream.hal
+++ b/automotive/evs/1.1/IEvsCameraStream.hal
@@ -17,15 +17,32 @@
 package android.hardware.automotive.evs@1.1;
 
 import @1.0::IEvsCameraStream;
+import @1.1::BufferDesc;
+import @1.1::EvsEvent;
 
 /**
  * Implemented on client side to receive asynchronous streaming event deliveries.
  */
 interface IEvsCameraStream extends @1.0::IEvsCameraStream {
+
+    /**
+     * Receives calls from the HAL each time a video frame is ready for inspection.
+     * Buffer handles received by this method must be returned via calls to
+     * IEvsCamera::doneWithFrame_1_1(). When the video stream is stopped via a call
+     * to IEvsCamera::stopVideoStream(), this callback may continue to happen for
+     * some time as the pipeline drains. Each frame must still be returned.
+     * When the last frame in the stream has been delivered, STREAM_STOPPED
+     * event must be delivered.  No further frame deliveries may happen
+     * thereafter.
+     *
+     * @param buffer a buffer descriptor of a delivered image frame.
+     */
+    oneway deliverFrame_1_1(BufferDesc buffer);
+
     /**
      * Receives calls from the HAL each time an event happens.
      *
      * @param  event EVS event with possible event information.
      */
-    oneway notifyEvent(EvsEvent event);
+    oneway notify(EvsEvent event);
 };
diff --git a/automotive/evs/1.1/IEvsEnumerator.hal b/automotive/evs/1.1/IEvsEnumerator.hal
new file mode 100644
index 0000000..1695821
--- /dev/null
+++ b/automotive/evs/1.1/IEvsEnumerator.hal
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.evs@1.1;
+
+import IEvsCamera;
+import @1.0::IEvsEnumerator;
+import @1.0::EvsResult;
+import android.hardware.camera.device@3.2::Stream;
+
+/**
+ * Provides the mechanism for EVS camera discovery
+ */
+interface IEvsEnumerator extends @1.0::IEvsEnumerator {
+    /**
+     * Returns a list of all EVS cameras available to the system
+     *
+     * @return cameras A list of cameras availale for EVS service.
+     */
+    getCameraList_1_1() generates (vec<CameraDesc> cameras);
+
+    /**
+     * Gets the IEvsCamera associated with a cameraId from a CameraDesc
+     *
+     * Given a camera's unique cameraId from CameraDesc, returns the
+     * IEvsCamera interface associated with the specified camera. When
+     * done using the camera, the caller may release it by calling closeCamera().
+     *
+     * @param  cameraId  A unique identifier of the camera.
+     * @param  streamCfg A stream configuration the client wants to use.
+     * @return evsCamera EvsCamera object associated with a given cameraId.
+     *                   Returned object would be null if a camera device does
+     *                   not support a given stream configuration or is already
+     *                   configured differently by another client.
+     */
+    openCamera_1_1(string cameraId, Stream streamCfg) generates (IEvsCamera evsCamera);
+};
diff --git a/automotive/evs/1.1/default/Android.bp b/automotive/evs/1.1/default/Android.bp
index a463471..41cb426 100644
--- a/automotive/evs/1.1/default/Android.bp
+++ b/automotive/evs/1.1/default/Android.bp
@@ -7,25 +7,41 @@
         "service.cpp",
         "EvsCamera.cpp",
         "EvsEnumerator.cpp",
-        "EvsDisplay.cpp"
+        "EvsDisplay.cpp",
+        "ConfigManager.cpp",
+        "ConfigManagerUtil.cpp",
     ],
     init_rc: ["android.hardware.automotive.evs@1.1-service.rc"],
 
     shared_libs: [
         "android.hardware.automotive.evs@1.0",
         "android.hardware.automotive.evs@1.1",
+        "android.hardware.camera.device@3.2",
         "libbase",
         "libbinder",
-        "libcutils",
+        "liblog",
         "libhardware",
         "libhidlbase",
         "liblog",
         "libui",
         "libutils",
+        "libcamera_metadata",
+        "libtinyxml2",
     ],
 
     cflags: [
         "-O0",
         "-g",
     ],
+
+    required: [
+        "evs_default_configuration.xml",
+    ],
+}
+
+prebuilt_etc {
+    name: "evs_default_configuration.xml",
+
+    src: "resources/evs_default_configuration.xml",
+    sub_dir: "automotive/evs",
 }
diff --git a/automotive/evs/1.1/default/ConfigManager.cpp b/automotive/evs/1.1/default/ConfigManager.cpp
new file mode 100644
index 0000000..4f46f9d
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.cpp
@@ -0,0 +1,487 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <sstream>
+#include <fstream>
+#include <thread>
+
+#include <hardware/gralloc.h>
+#include <utils/SystemClock.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+
+#include "ConfigManager.h"
+
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+
+
+ConfigManager::~ConfigManager() {
+    /* Nothing to do */
+}
+
+
+void ConfigManager::readCameraInfo(const XMLElement * const aCameraElem) {
+    if (aCameraElem == nullptr) {
+        ALOGW("XML file does not have required camera element");
+        return;
+    }
+
+    const XMLElement *curElem = aCameraElem->FirstChildElement();
+    while (curElem != nullptr) {
+        if (!strcmp(curElem->Name(), "group")) {
+            /* camera group identifier */
+            const char *group_id = curElem->FindAttribute("group_id")->Value();
+
+            /* create CameraGroup */
+            unique_ptr<ConfigManager::CameraGroup> aCameraGroup(new ConfigManager::CameraGroup());
+
+            /* add a camera device to its group */
+            addCameraDevices(curElem->FindAttribute("device_id")->Value(), aCameraGroup);
+
+            /* a list of camera stream configurations */
+            const XMLElement *childElem =
+                curElem->FirstChildElement("caps")->FirstChildElement("stream");
+            while (childElem != nullptr) {
+                /* read 5 attributes */
+                const XMLAttribute *idAttr     = childElem->FindAttribute("id");
+                const XMLAttribute *widthAttr  = childElem->FindAttribute("width");
+                const XMLAttribute *heightAttr = childElem->FindAttribute("height");
+                const XMLAttribute *fmtAttr    = childElem->FindAttribute("format");
+                const XMLAttribute *fpsAttr    = childElem->FindAttribute("framerate");
+
+                const int32_t id = stoi(idAttr->Value());
+                int32_t framerate = 0;
+                if (fpsAttr != nullptr) {
+                    framerate = stoi(fpsAttr->Value());
+                }
+
+                int32_t pixFormat;
+                if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+                                                            pixFormat)) {
+                    RawStreamConfiguration cfg = {
+                        id,
+                        stoi(widthAttr->Value()),
+                        stoi(heightAttr->Value()),
+                        pixFormat,
+                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+                        framerate
+                    };
+                    aCameraGroup->streamConfigurations[id] = cfg;
+                }
+
+                childElem = childElem->NextSiblingElement("stream");
+            }
+
+            /* camera group synchronization */
+            const char *sync = curElem->FindAttribute("synchronized")->Value();
+            aCameraGroup->synchronized =
+                static_cast<bool>(strcmp(sync, "false"));
+
+            /* add a group to hash map */
+            mCameraGroups[group_id] = std::move(aCameraGroup);
+        } else if (!strcmp(curElem->Name(), "device")) {
+            /* camera unique identifier */
+            const char *id = curElem->FindAttribute("id")->Value();
+
+            /* camera mount location */
+            const char *pos = curElem->FindAttribute("position")->Value();
+
+            /* store read camera module information */
+            mCameraInfo[id] = readCameraDeviceInfo(curElem);
+
+            /* assign a camera device to a position group */
+            mCameraPosition[pos].emplace(id);
+        } else {
+            /* ignore other device types */
+            ALOGD("Unknown element %s is ignored", curElem->Name());
+        }
+
+        curElem = curElem->NextSiblingElement();
+    }
+}
+
+
+unique_ptr<ConfigManager::CameraInfo>
+ConfigManager::readCameraDeviceInfo(const XMLElement *aDeviceElem) {
+    if (aDeviceElem == nullptr) {
+        return nullptr;
+    }
+
+    /* create a CameraInfo to be filled */
+    unique_ptr<ConfigManager::CameraInfo> aCamera(new ConfigManager::CameraInfo());
+
+    /* size information to allocate camera_metadata_t */
+    size_t totalEntries = 0;
+    size_t totalDataSize = 0;
+
+    /* read device capabilities */
+    totalEntries +=
+        readCameraCapabilities(aDeviceElem->FirstChildElement("caps"),
+                               aCamera,
+                               totalDataSize);
+
+
+    /* read camera metadata */
+    totalEntries +=
+        readCameraMetadata(aDeviceElem->FirstChildElement("characteristics"),
+                           aCamera,
+                           totalDataSize);
+
+    /* construct camera_metadata_t */
+    if (!constructCameraMetadata(aCamera, totalEntries, totalDataSize)) {
+        ALOGW("Either failed to allocate memory or "
+              "allocated memory was not large enough");
+    }
+
+    return aCamera;
+}
+
+
+size_t ConfigManager::readCameraCapabilities(const XMLElement * const aCapElem,
+                                             unique_ptr<ConfigManager::CameraInfo> &aCamera,
+                                             size_t &dataSize) {
+    if (aCapElem == nullptr) {
+        return 0;
+    }
+
+    string token;
+    const XMLElement *curElem = nullptr;
+
+    /* a list of supported camera parameters/controls */
+    curElem = aCapElem->FirstChildElement("supported_controls");
+    if (curElem != nullptr) {
+        const XMLElement *ctrlElem = curElem->FirstChildElement("control");
+        while (ctrlElem != nullptr) {
+            const char *nameAttr = ctrlElem->FindAttribute("name")->Value();;
+            const int32_t minVal = stoi(ctrlElem->FindAttribute("min")->Value());
+            const int32_t maxVal = stoi(ctrlElem->FindAttribute("max")->Value());
+
+            int32_t stepVal = 1;
+            const XMLAttribute *stepAttr = ctrlElem->FindAttribute("step");
+            if (stepAttr != nullptr) {
+                stepVal = stoi(stepAttr->Value());
+            }
+
+            CameraParam aParam;
+            if (ConfigManagerUtil::convertToEvsCameraParam(nameAttr,
+                                                           aParam)) {
+                aCamera->controls.emplace(
+                    aParam,
+                    make_tuple(minVal, maxVal, stepVal)
+                );
+            }
+
+            ctrlElem = ctrlElem->NextSiblingElement("control");
+        }
+    }
+
+    /* a list of camera stream configurations */
+    curElem = aCapElem->FirstChildElement("stream");
+    while (curElem != nullptr) {
+        /* read 5 attributes */
+        const XMLAttribute *idAttr     = curElem->FindAttribute("id");
+        const XMLAttribute *widthAttr  = curElem->FindAttribute("width");
+        const XMLAttribute *heightAttr = curElem->FindAttribute("height");
+        const XMLAttribute *fmtAttr    = curElem->FindAttribute("format");
+        const XMLAttribute *fpsAttr    = curElem->FindAttribute("framerate");
+
+        const int32_t id = stoi(idAttr->Value());
+        int32_t framerate = 0;
+        if (fpsAttr != nullptr) {
+            framerate = stoi(fpsAttr->Value());
+        }
+
+        int32_t pixFormat;
+        if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+                                                    pixFormat)) {
+            RawStreamConfiguration cfg = {
+                id,
+                stoi(widthAttr->Value()),
+                stoi(heightAttr->Value()),
+                pixFormat,
+                ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT,
+                framerate
+            };
+            aCamera->streamConfigurations[id] = cfg;
+        }
+
+        curElem = curElem->NextSiblingElement("stream");
+    }
+
+    dataSize = calculate_camera_metadata_entry_data_size(
+                   get_camera_metadata_tag_type(
+                       ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS
+                   ),
+                   aCamera->streamConfigurations.size() * kStreamCfgSz
+               );
+
+    /* a single camera metadata entry contains multiple stream configurations */
+    return dataSize > 0 ? 1 : 0;
+}
+
+
+size_t ConfigManager::readCameraMetadata(const XMLElement * const aParamElem,
+                                       unique_ptr<ConfigManager::CameraInfo> &aCamera,
+                                       size_t &dataSize) {
+    if (aParamElem == nullptr) {
+        return 0;
+    }
+
+    const XMLElement *curElem = aParamElem->FirstChildElement("parameter");
+    size_t numEntries = 0;
+    camera_metadata_tag_t tag;
+    while (curElem != nullptr) {
+        if (!ConfigManagerUtil::convertToMetadataTag(curElem->FindAttribute("name")->Value(),
+                                                     tag)) {
+            switch(tag) {
+                case ANDROID_LENS_DISTORTION:
+                case ANDROID_LENS_POSE_ROTATION:
+                case ANDROID_LENS_POSE_TRANSLATION:
+                case ANDROID_LENS_INTRINSIC_CALIBRATION: {
+                    /* float[] */
+                    size_t count = 0;
+                    void   *data = ConfigManagerUtil::convertFloatArray(
+                                        curElem->FindAttribute("size")->Value(),
+                                        curElem->FindAttribute("value")->Value(),
+                                        count
+                                   );
+
+                    aCamera->cameraMetadata[tag] =
+                        make_pair(make_unique<void *>(data), count);
+
+                    ++numEntries;
+                    dataSize += calculate_camera_metadata_entry_data_size(
+                                    get_camera_metadata_tag_type(tag), count
+                                );
+
+                    break;
+                }
+
+                default:
+                    ALOGW("Parameter %s is not supported",
+                          curElem->FindAttribute("name")->Value());
+                    break;
+            }
+        }
+
+        curElem = curElem->NextSiblingElement("parameter");
+    }
+
+    return numEntries;
+}
+
+
+bool ConfigManager::constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+                                            const size_t totalEntries,
+                                            const size_t totalDataSize) {
+    if (!aCamera->allocate(totalEntries, totalDataSize)) {
+        ALOGE("Failed to allocate memory for camera metadata");
+        return false;
+    }
+
+    const size_t numStreamConfigs = aCamera->streamConfigurations.size();
+    unique_ptr<int32_t[]> data(new int32_t[kStreamCfgSz * numStreamConfigs]);
+    int32_t *ptr = data.get();
+    for (auto &cfg : aCamera->streamConfigurations) {
+        for (auto i = 0; i < kStreamCfgSz; ++i) {
+          *ptr++ = cfg.second[i];
+        }
+    }
+    int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+                                            ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                                            data.get(),
+                                            numStreamConfigs * kStreamCfgSz);
+
+    if (err) {
+        ALOGE("Failed to add stream configurations to metadata, ignored");
+        return false;
+    }
+
+    bool success = true;
+    for (auto &[tag, entry] : aCamera->cameraMetadata) {
+        /* try to add new camera metadata entry */
+        int32_t err = add_camera_metadata_entry(aCamera->characteristics,
+                                                tag,
+                                                entry.first.get(),
+                                                entry.second);
+        if (err) {
+            ALOGE("Failed to add an entry with a tag 0x%X", tag);
+
+            /* may exceed preallocated capacity */
+            ALOGE("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+                  get_camera_metadata_entry_count(aCamera->characteristics),
+                  get_camera_metadata_entry_capacity(aCamera->characteristics),
+                  get_camera_metadata_data_count(aCamera->characteristics),
+                  get_camera_metadata_data_capacity(aCamera->characteristics));
+            ALOGE("\tCurrent metadata entry requires %ld bytes",
+                  calculate_camera_metadata_entry_data_size(tag, entry.second));
+
+            success = false;
+        }
+    }
+
+    ALOGV("Camera metadata has %ld / %ld entries and %ld / %ld bytes are filled",
+          get_camera_metadata_entry_count(aCamera->characteristics),
+          get_camera_metadata_entry_capacity(aCamera->characteristics),
+          get_camera_metadata_data_count(aCamera->characteristics),
+          get_camera_metadata_data_capacity(aCamera->characteristics));
+
+    return success;
+}
+
+
+void ConfigManager::readSystemInfo(const XMLElement * const aSysElem) {
+    if (aSysElem == nullptr) {
+        return;
+    }
+
+    /*
+     * Please note that this function assumes that a given system XML element
+     * and its child elements follow DTD.  If it does not, it will cause a
+     * segmentation fault due to the failure of finding expected attributes.
+     */
+
+    /* read number of cameras available in the system */
+    const XMLElement *xmlElem = aSysElem->FirstChildElement("num_cameras");
+    if (xmlElem != nullptr) {
+        mSystemInfo.numCameras =
+            stoi(xmlElem->FindAttribute("value")->Value());
+    }
+}
+
+
+void ConfigManager::readDisplayInfo(const XMLElement * const aDisplayElem) {
+    if (aDisplayElem == nullptr) {
+        ALOGW("XML file does not have required camera element");
+        return;
+    }
+
+    const XMLElement *curDev = aDisplayElem->FirstChildElement("device");
+    while (curDev != nullptr) {
+        const char *id = curDev->FindAttribute("id")->Value();
+        //const char *pos = curDev->FirstAttribute("position")->Value();
+
+        unique_ptr<DisplayInfo> dpy(new DisplayInfo());
+        if (dpy == nullptr) {
+            ALOGE("Failed to allocate memory for DisplayInfo");
+            return;
+        }
+
+        const XMLElement *cap = curDev->FirstChildElement("caps");
+        if (cap != nullptr) {
+            const XMLElement *curStream = cap->FirstChildElement("stream");
+            while (curStream != nullptr) {
+                /* read 4 attributes */
+                const XMLAttribute *idAttr     = curStream->FindAttribute("id");
+                const XMLAttribute *widthAttr  = curStream->FindAttribute("width");
+                const XMLAttribute *heightAttr = curStream->FindAttribute("height");
+                const XMLAttribute *fmtAttr    = curStream->FindAttribute("format");
+
+                const int32_t id = stoi(idAttr->Value());
+                int32_t pixFormat;
+                if (ConfigManagerUtil::convertToPixelFormat(fmtAttr->Value(),
+                                                            pixFormat)) {
+                    RawStreamConfiguration cfg = {
+                        id,
+                        stoi(widthAttr->Value()),
+                        stoi(heightAttr->Value()),
+                        pixFormat,
+                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT,
+                        0   // unused
+                    };
+                    dpy->streamConfigurations[id] = cfg;
+                }
+
+                curStream = curStream->NextSiblingElement("stream");
+            }
+        }
+
+        mDisplayInfo[id] = std::move(dpy);
+        curDev = curDev->NextSiblingElement("device");
+    }
+
+    return;
+}
+
+
+bool ConfigManager::readConfigDataFromXML() noexcept {
+    XMLDocument xmlDoc;
+
+    const int64_t parsingStart = android::elapsedRealtimeNano();
+
+    /* load and parse a configuration file */
+    xmlDoc.LoadFile(mConfigFilePath);
+    if (xmlDoc.ErrorID() != XML_SUCCESS) {
+        ALOGE("Failed to load and/or parse a configuration file, %s", xmlDoc.ErrorStr());
+        return false;
+    }
+
+    /* retrieve the root element */
+    const XMLElement *rootElem = xmlDoc.RootElement();
+    if (strcmp(rootElem->Name(), "configuration")) {
+        ALOGE("A configuration file is not in the required format.  "
+              "See /etc/automotive/evs/evs_configuration.dtd");
+        return false;
+    }
+
+    /*
+     * parse camera information; this needs to be done before reading system
+     * information
+     */
+    readCameraInfo(rootElem->FirstChildElement("camera"));
+
+    /* parse system information */
+    readSystemInfo(rootElem->FirstChildElement("system"));
+
+    /* parse display information */
+    readDisplayInfo(rootElem->FirstChildElement("display"));
+
+    const int64_t parsingEnd = android::elapsedRealtimeNano();
+    ALOGI("Parsing configuration file takes %lf (ms)",
+          (double)(parsingEnd - parsingStart) / 1000000.0);
+
+
+    return true;
+}
+
+
+void ConfigManager::addCameraDevices(const char *devices,
+                                     unique_ptr<CameraGroup> &aGroup) {
+    stringstream device_list(devices);
+    string token;
+    while (getline(device_list, token, ',')) {
+        aGroup->devices.emplace(token);
+    }
+}
+
+
+std::unique_ptr<ConfigManager> ConfigManager::Create(const char *path) {
+    unique_ptr<ConfigManager> cfgMgr(new ConfigManager(path));
+
+    /*
+     * Read a configuration from XML file
+     *
+     * If this is too slow, ConfigManager::readConfigDataFromBinary() and
+     * ConfigManager::writeConfigDataToBinary()can serialize CameraInfo object
+     * to the filesystem and construct CameraInfo instead; this was
+     * evaluated as 10x faster.
+     */
+    if (!cfgMgr->readConfigDataFromXML()) {
+        return nullptr;
+    } else {
+        return cfgMgr;
+    }
+}
+
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
new file mode 100644
index 0000000..0275f90
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 CONFIG_MANAGER_H
+#define CONFIG_MANAGER_H
+
+#include <vector>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <tinyxml2.h>
+
+#include <system/camera_metadata.h>
+#include <log/log.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+#include "ConfigManagerUtil.h"
+
+using namespace std;
+using namespace tinyxml2;
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+/*
+ * Plese note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 6;
+typedef std::array<int32_t, kStreamCfgSz> RawStreamConfiguration;
+
+class ConfigManager {
+public:
+    static std::unique_ptr<ConfigManager> Create(const char *path = "");
+    ConfigManager(const ConfigManager&) = delete;
+    ConfigManager& operator=(const ConfigManager&) = delete;
+
+    virtual ~ConfigManager();
+
+    /* Camera device's capabilities and metadata */
+    class CameraInfo {
+    public:
+        CameraInfo() :
+            characteristics(nullptr) {
+            /* Nothing to do */
+        }
+
+        virtual ~CameraInfo() {
+            free_camera_metadata(characteristics);
+        }
+
+        /* Allocate memory for camera_metadata_t */
+        bool allocate(size_t entry_cap, size_t data_cap) {
+            if (characteristics != nullptr) {
+                ALOGE("Camera metadata is already allocated");
+                return false;
+            }
+
+            characteristics = allocate_camera_metadata(entry_cap, data_cap);
+            return characteristics != nullptr;
+        }
+
+        /*
+         * List of supported controls that the master client can program.
+         * Paraemters are stored with its valid range
+         */
+        unordered_map<CameraParam,
+                      tuple<int32_t, int32_t, int32_t>> controls;
+
+        /* List of supported frame rates */
+        unordered_set<int32_t> frameRates;
+
+        /*
+         * List of supported output stream configurations; each array stores
+         * format, width, height, and direction values in the order.
+         */
+        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+
+        /*
+         * Internal storage for camera metadata.  Each entry holds a pointer to
+         * data and number of elements
+         */
+        unordered_map<camera_metadata_tag_t,
+                      pair<unique_ptr<void *>, size_t>> cameraMetadata;
+
+        /* Camera module characteristics */
+        camera_metadata_t *characteristics;
+    };
+
+    class CameraGroup {
+    public:
+        CameraGroup() {}
+
+        /* ID of member camera devices */
+        unordered_set<string> devices;
+
+        /* The capture operation of member camera devices are synchronized */
+        bool synchronized = false;
+
+        /*
+         * List of stream configurations that are supposed by all camera devices
+         * in this group.
+         */
+        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+    };
+
+    class SystemInfo {
+    public:
+        /* number of available cameras */
+        int32_t numCameras = 0;
+    };
+
+    class DisplayInfo {
+    public:
+        /*
+         * List of supported input stream configurations; each array stores
+         * format, width, height, and direction values in the order.
+         */
+        unordered_map<int32_t, RawStreamConfiguration> streamConfigurations;
+    };
+
+    /*
+     * Return system information
+     *
+     * @return SystemInfo
+     *         Constant reference of SystemInfo.
+     */
+    const SystemInfo &getSystemInfo() {
+        return mSystemInfo;
+    }
+
+    /*
+     * Return a list of cameras
+     *
+     * This function assumes that it is not being called frequently.
+     *
+     * @return vector<string>
+     *         A vector that contains unique camera device identifiers.
+     */
+    vector<string> getCameraList() {
+        vector<string> aList;
+        for (auto &v : mCameraInfo) {
+            aList.emplace_back(v.first);
+        }
+
+        return aList;
+    }
+
+
+    /*
+     * Return a list of cameras
+     *
+     * @return CameraGroup
+     *         A pointer to a camera group identified by a given id.
+     */
+    unique_ptr<CameraGroup>& getCameraGroup(const string& gid) {
+        return mCameraGroups[gid];
+    }
+
+
+    /*
+     * Return a camera metadata
+     *
+     * @param  cameraId
+     *         Unique camera node identifier in string
+     *
+     * @return unique_ptr<CameraInfo>
+     *         A pointer to CameraInfo that is associated with a given camera
+     *         ID.  This returns a null pointer if this does not recognize a
+     *         given camera identifier.
+     */
+    unique_ptr<CameraInfo>& getCameraInfo(const string cameraId) noexcept {
+        return mCameraInfo[cameraId];
+    }
+
+private:
+    /* Constructors */
+    ConfigManager(const char *xmlPath) :
+        mConfigFilePath(xmlPath) {
+    }
+
+    /* System configuration */
+    SystemInfo mSystemInfo;
+
+    /* Internal data structure for camera device information */
+    unordered_map<string, unique_ptr<CameraInfo>> mCameraInfo;
+
+    /* Internal data structure for camera device information */
+    unordered_map<string, unique_ptr<DisplayInfo>> mDisplayInfo;
+
+    /* Camera groups are stored in <groud id, CameraGroup> hash map */
+    unordered_map<string, unique_ptr<CameraGroup>> mCameraGroups;
+
+    /*
+     * Camera positions are stored in <position, camera id set> hash map.
+     * The position must be one of front, rear, left, and right.
+     */
+    unordered_map<string, unordered_set<string>>  mCameraPosition;
+
+    /* A path to XML configuration file */
+    const char *mConfigFilePath;
+
+    /*
+     * Parse a given EVS configuration file and store the information
+     * internally.
+     *
+     * @return bool
+     *         True if it completes parsing a file successfully.
+     */
+    bool readConfigDataFromXML() noexcept;
+
+    /*
+     * read the information of the vehicle
+     *
+     * @param  aSysElem
+     *         A pointer to "system" XML element.
+     */
+    void readSystemInfo(const XMLElement * const aSysElem);
+
+    /*
+     * read the information of camera devices
+     *
+     * @param  aCameraElem
+     *         A pointer to "camera" XML element that may contain multiple
+     *         "device" elements.
+     */
+    void readCameraInfo(const XMLElement * const aCameraElem);
+
+    /*
+     * read display device information
+     *
+     * @param  aDisplayElem
+     *         A pointer to "display" XML element that may contain multiple
+     *         "device" elements.
+     */
+    void readDisplayInfo(const XMLElement * const aDisplayElem);
+
+    /*
+     * read camera device information
+     *
+     * @param  aDeviceElem
+     *         A pointer to "device" XML element that contains camera module
+     *         capability info and its characteristics.
+     *
+     * @return unique_ptr<CameraInfo>
+     *         A pointer to CameraInfo class that contains camera module
+     *         capability and characteristics.  Please note that this transfers
+     *         the ownership of created CameraInfo to the caller.
+     */
+    unique_ptr<CameraInfo> readCameraDeviceInfo(const XMLElement *aDeviceElem);
+
+    /*
+     * read camera metadata
+     *
+     * @param  aCapElem
+     *         A pointer to "cap" XML element.
+     * @param  aCamera
+     *         A pointer to CameraInfo that is being filled by this method.
+     * @param  dataSize
+     *         Required size of memory to store camera metadata found in this
+     *         method.  This is calculated in this method and returned to the
+     *         caller for camera_metadata allocation.
+     *
+     * @return size_t
+     *         Number of camera metadata entries
+     */
+    size_t readCameraCapabilities(const XMLElement * const aCapElem,
+                                  unique_ptr<CameraInfo> &aCamera,
+                                  size_t &dataSize);
+
+    /*
+     * read camera metadata
+     *
+     * @param  aParamElem
+     *         A pointer to "characteristics" XML element.
+     * @param  aCamera
+     *         A pointer to CameraInfo that is being filled by this method.
+     * @param  dataSize
+     *         Required size of memory to store camera metadata found in this
+     *         method.
+     *
+     * @return size_t
+     *         Number of camera metadata entries
+     */
+    size_t readCameraMetadata(const XMLElement * const aParamElem,
+                              unique_ptr<CameraInfo> &aCamera,
+                              size_t &dataSize);
+
+    /*
+     * construct camera_metadata_t from camera capabilities and metadata
+     *
+     * @param  aCamera
+     *         A pointer to CameraInfo that is being filled by this method.
+     * @param  totalEntries
+     *         Number of camera metadata entries to be added.
+     * @param  totalDataSize
+     *         Sum of sizes of camera metadata entries to be added.
+     *
+     * @return bool
+     *         False if either it fails to allocate memory for camera metadata
+     *         or its size is not large enough to add all found camera metadata
+     *         entries.
+     */
+    bool constructCameraMetadata(unique_ptr<CameraInfo> &aCamera,
+                                 const size_t totalEntries,
+                                 const size_t totalDataSize);
+
+    /*
+     * parse a comma-separated list of camera devices and add them to
+     * CameraGroup.
+     *
+     * @param  devices
+     *         A comma-separated list of camera device identifiers.
+     * @param  aGroup
+     *         Camera group which cameras will be added to.
+     */
+    void addCameraDevices(const char *devices,
+                          unique_ptr<CameraGroup> &aGroup);
+};
+#endif // CONFIG_MANAGER_H
+
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.cpp b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
new file mode 100644
index 0000000..8206daa
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConfigManagerUtil.h"
+
+#include <string>
+#include <sstream>
+#include <linux/videodev2.h>
+
+#include <log/log.h>
+#include <system/graphics-base-v1.0.h>
+
+
+bool ConfigManagerUtil::convertToEvsCameraParam(const string &id,
+                                                CameraParam &camParam) {
+    string trimmed = ConfigManagerUtil::trimString(id);
+    bool success = true;
+
+    if (!trimmed.compare("BRIGHTNESS")) {
+        camParam =  CameraParam::BRIGHTNESS;
+    } else if (!trimmed.compare("CONTRAST")) {
+        camParam =  CameraParam::CONTRAST;
+    } else if (!trimmed.compare("AUTOGAIN")) {
+        camParam =  CameraParam::AUTOGAIN;
+    } else if (!trimmed.compare("GAIN")) {
+        camParam =  CameraParam::GAIN;
+    } else if (!trimmed.compare("AUTO_WHITE_BALANCE")) {
+        camParam =  CameraParam::AUTO_WHITE_BALANCE;
+    } else if (!trimmed.compare("WHITE_BALANCE_TEMPERATURE")) {
+        camParam =  CameraParam::WHITE_BALANCE_TEMPERATURE;
+    } else if (!trimmed.compare("SHARPNESS")) {
+        camParam =  CameraParam::SHARPNESS;
+    } else if (!trimmed.compare("AUTO_EXPOSURE")) {
+        camParam =  CameraParam::AUTO_EXPOSURE;
+    } else if (!trimmed.compare("ABSOLUTE_EXPOSURE")) {
+        camParam =  CameraParam::ABSOLUTE_EXPOSURE;
+    } else if (!trimmed.compare("ABSOLUTE_FOCUS")) {
+        camParam =  CameraParam::ABSOLUTE_FOCUS;
+    } else if (!trimmed.compare("AUTO_FOCUS")) {
+        camParam =  CameraParam::AUTO_FOCUS;
+    } else if (!trimmed.compare("ABSOLUTE_ZOOM")) {
+        camParam =  CameraParam::ABSOLUTE_ZOOM;
+    } else {
+        success = false;
+    }
+
+    return success;
+}
+
+
+bool ConfigManagerUtil::convertToPixelFormat(const string &format,
+                                             int32_t &pixFormat) {
+    string trimmed = ConfigManagerUtil::trimString(format);
+    bool success = true;
+
+    if (!trimmed.compare("RGBA_8888")) {
+        pixFormat =  HAL_PIXEL_FORMAT_RGBA_8888;
+    } else if (!trimmed.compare("YCRCB_420_SP")) {
+        pixFormat =  HAL_PIXEL_FORMAT_YCRCB_420_SP;
+    } else if (!trimmed.compare("YCBCR_422_I")) {
+        pixFormat =  HAL_PIXEL_FORMAT_YCBCR_422_I;
+    } else {
+        success = false;
+    }
+
+    return success;
+}
+
+
+bool ConfigManagerUtil::convertToMetadataTag(const char *name,
+                                             camera_metadata_tag &aTag) {
+    if (!strcmp(name, "LENS_DISTORTION")) {
+        aTag =  ANDROID_LENS_DISTORTION;
+    } else if (!strcmp(name, "LENS_INTRINSIC_CALIBRATION")) {
+        aTag =  ANDROID_LENS_INTRINSIC_CALIBRATION;
+    } else if (!strcmp(name, "LENS_POSE_ROTATION")) {
+        aTag =  ANDROID_LENS_POSE_ROTATION;
+    } else if (!strcmp(name, "LENS_POSE_TRANSLATION")) {
+        aTag =  ANDROID_LENS_POSE_TRANSLATION;
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+
+float *ConfigManagerUtil::convertFloatArray(const char *sz, const char *vals,
+                                            size_t &count, const char delimiter) {
+    string size_string(sz);
+    string value_string(vals);
+
+    count = stoi(size_string);
+    float *result = new float[count];
+    stringstream values(value_string);
+
+    int32_t idx = 0;
+    string token;
+    while (getline(values, token, delimiter)) {
+        result[idx++] = stof(token);
+    }
+
+    return result;
+}
+
+
+string ConfigManagerUtil::trimString(const string &src, const string &ws) {
+    const auto s = src.find_first_not_of(ws);
+    if (s == string::npos) {
+        return "";
+    }
+
+    const auto e = src.find_last_not_of(ws);
+    const auto r = e - s + 1;
+
+    return src.substr(s, r);
+}
+
diff --git a/automotive/evs/1.1/default/ConfigManagerUtil.h b/automotive/evs/1.1/default/ConfigManagerUtil.h
new file mode 100644
index 0000000..8c89ae7
--- /dev/null
+++ b/automotive/evs/1.1/default/ConfigManagerUtil.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 CONFIG_MANAGER_UTIL_H
+#define CONFIG_MANAGER_UTIL_H
+
+#include <utility>
+#include <string>
+#include <system/camera_metadata.h>
+#include <android/hardware/automotive/evs/1.1/types.h>
+
+using namespace std;
+using ::android::hardware::automotive::evs::V1_1::CameraParam;
+
+
+class ConfigManagerUtil {
+public:
+    /**
+     * Convert a given string into V4L2_CID_*
+     */
+    static bool convertToEvsCameraParam(const string &id,
+                                        CameraParam &camParam);
+    /**
+     * Convert a given string into android.hardware.graphics.common.PixelFormat
+     */
+    static bool convertToPixelFormat(const string &format,
+                                     int32_t &pixelFormat);
+    /**
+     * Convert a given string into corresponding camera metadata data tag defined in
+     * system/media/camera/include/system/camera_metadta_tags.h
+     */
+    static bool convertToMetadataTag(const char *name,
+                                     camera_metadata_tag &aTag);
+    /**
+     * Convert a given string into a floating value array
+     */
+    static float *convertFloatArray(const char *sz,
+                                    const char *vals,
+                                    size_t &count,
+                                    const char delimiter = ',');
+    /**
+     * Trim a string
+     */
+    static string trimString(const string &src,
+                             const string &ws = " \n\r\t\f\v");
+};
+
+#endif // CONFIG_MANAGER_UTIL_H
+
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
index 2d55566..5ba753d 100644
--- a/automotive/evs/1.1/default/EvsCamera.cpp
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -40,28 +40,21 @@
 const unsigned MAX_BUFFERS_IN_FLIGHT = 100;
 
 
-EvsCamera::EvsCamera(const char *id) :
+EvsCamera::EvsCamera(const char *id,
+                     unique_ptr<ConfigManager::CameraInfo> &camInfo) :
         mFramesAllowed(0),
         mFramesInUse(0),
-        mStreamState(STOPPED) {
+        mStreamState(STOPPED),
+        mCameraInfo(camInfo) {
 
     ALOGD("EvsCamera instantiated");
 
-    mDescription.cameraId = id;
+    /* set a camera id */
+    mDescription.v1.cameraId = id;
 
-    // Set up dummy data for testing
-    if (mDescription.cameraId == kCameraName_Backup) {
-        mWidth  = 640;          // full NTSC/VGA
-        mHeight = 480;          // full NTSC/VGA
-        mDescription.vendorFlags = 0xFFFFFFFF;   // Arbitrary value
-    } else {
-        mWidth  = 320;          // 1/2 NTSC/VGA
-        mHeight = 240;          // 1/2 NTSC/VGA
-    }
-
-    mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-    mUsage  = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
-              GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+    /* set camera metadata */
+    mDescription.metadata.setToExternal((uint8_t *)camInfo->characteristics,
+                                        get_camera_metadata_size(camInfo->characteristics));
 }
 
 
@@ -109,7 +102,7 @@
     ALOGD("getCameraInfo");
 
     // Send back our self description
-    _hidl_cb(mDescription);
+    _hidl_cb(mDescription.v1);
     return Void();
 }
 
@@ -194,7 +187,7 @@
 
         // Block outside the mutex until the "stop" flag has been acknowledged
         // We won't send any more frames, but the client might still get some already in flight
-        ALOGD("Waiting for stream thread to end..");
+        ALOGD("Waiting for stream thread to end...");
         lock.unlock();
         mCaptureThread.join();
         lock.lock();
@@ -238,6 +231,15 @@
 
 
 // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+Return<void> EvsCamera::getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb) {
+    ALOGD("getCameraInfo_1_1");
+
+    // Send back our self description
+    _hidl_cb(mDescription);
+    return Void();
+}
+
+
 Return<EvsResult> EvsCamera::doneWithFrame_1_1(const BufferDesc_1_1& bufDesc)  {
     std::lock_guard <std::mutex> lock(mAccessLock);
     returnBuffer(bufDesc.bufferId, bufDesc.buffer.nativeHandle);
@@ -278,8 +280,29 @@
 }
 
 
-Return<void> EvsCamera::setParameter(CameraParam id, int32_t value,
-                                     setParameter_cb _hidl_cb) {
+Return<void> EvsCamera::getParameterList(getParameterList_cb _hidl_cb) {
+    hidl_vec<CameraParam> hidlCtrls;
+    hidlCtrls.resize(mCameraInfo->controls.size());
+    unsigned idx = 0;
+    for (auto& [cid, cfg] : mCameraInfo->controls) {
+        hidlCtrls[idx++] = cid;
+    }
+
+    _hidl_cb(hidlCtrls);
+    return Void();
+}
+
+
+Return<void> EvsCamera::getIntParameterRange(CameraParam id,
+                                             getIntParameterRange_cb _hidl_cb) {
+    auto range = mCameraInfo->controls[id];
+    _hidl_cb(get<0>(range), get<1>(range), get<2>(range));
+    return Void();
+}
+
+
+Return<void> EvsCamera::setIntParameter(CameraParam id, int32_t value,
+                                        setIntParameter_cb _hidl_cb) {
     // Default implementation does not support this.
     (void)id;
     (void)value;
@@ -288,7 +311,8 @@
 }
 
 
-Return<void> EvsCamera::getParameter(CameraParam id, getParameter_cb _hidl_cb) {
+Return<void> EvsCamera::getIntParameter(CameraParam id,
+                                        getIntParameter_cb _hidl_cb) {
     // Default implementation does not support this.
     (void)id;
     _hidl_cb(EvsResult::INVALID_ARG, 0);
@@ -471,9 +495,7 @@
             fillTestFrame(newBuffer);
 
             // Issue the (asynchronous) callback to the client -- can't be holding the lock
-            EvsEvent event;
-            event.buffer(newBuffer);
-            auto result = mStream->notifyEvent(event);
+            auto result = mStream->deliverFrame_1_1(newBuffer);
             if (result.isOk()) {
                 ALOGD("Delivered %p as id %d",
                       newBuffer.buffer.nativeHandle.getNativeHandle(), newBuffer.bufferId);
@@ -506,10 +528,8 @@
 
     // If we've been asked to stop, send an event to signal the actual end of stream
     EvsEvent event;
-    InfoEventDesc desc = {};
-    desc.aType = InfoEventType::STREAM_STOPPED;
-    event.info(desc);
-    auto result = mStream->notifyEvent(event);
+    event.aType = EvsEventType::STREAM_STOPPED;
+    auto result = mStream->notify(event);
     if (!result.isOk()) {
         ALOGE("Error delivering end of stream marker");
     }
@@ -616,6 +636,38 @@
 }
 
 
+sp<EvsCamera> EvsCamera::Create(const char *deviceName) {
+    unique_ptr<ConfigManager::CameraInfo> nullCamInfo = nullptr;
+
+    return Create(deviceName, nullCamInfo);
+}
+
+
+sp<EvsCamera> EvsCamera::Create(const char *deviceName,
+                                unique_ptr<ConfigManager::CameraInfo> &camInfo,
+                                const Stream *streamCfg) {
+    sp<EvsCamera> evsCamera = new EvsCamera(deviceName, camInfo);
+    if (evsCamera == nullptr) {
+        return nullptr;
+    }
+
+    /* default implementation does not use a given configuration */
+    (void)streamCfg;
+
+    /* Use the first resolution from the list for the testing */
+    auto it = camInfo->streamConfigurations.begin();
+    evsCamera->mWidth = it->second[1];
+    evsCamera->mHeight = it->second[2];
+    evsCamera->mDescription.v1.vendorFlags = 0xFFFFFFFF; // Arbitrary test value
+
+    evsCamera->mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+    evsCamera->mUsage  = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_CAMERA_WRITE |
+                         GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_RARELY;
+
+    return evsCamera;
+}
+
+
 } // namespace implementation
 } // namespace V1_0
 } // namespace evs
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
index 47a3164..c15b4b1 100644
--- a/automotive/evs/1.1/default/EvsCamera.h
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -25,6 +25,8 @@
 
 #include <thread>
 
+#include "ConfigManager.h"
+
 using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
 using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
 using IEvsCameraStream_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCameraStream;
@@ -59,18 +61,28 @@
     Return<EvsResult> setExtendedInfo(uint32_t opaqueIdentifier, int32_t opaqueValue) override;
 
     // Methods from ::android::hardware::automotive::evs::V1_1::IEvsCamera follow.
+    Return<void>      getCameraInfo_1_1(getCameraInfo_1_1_cb _hidl_cb)  override;
     Return<EvsResult> pauseVideoStream() override;
     Return<EvsResult> resumeVideoStream() override;
     Return<EvsResult> doneWithFrame_1_1(const BufferDesc_1_1& buffer) override;
     Return<EvsResult> setMaster() override;
     Return<EvsResult> forceMaster(const sp<IEvsDisplay>& display) override;
     Return<EvsResult> unsetMaster() override;
-    Return<void>      setParameter(CameraParam id, int32_t value,
-                                   setParameter_cb _hidl_cb) override;
-    Return<void>      getParameter(CameraParam id, getParameter_cb _hidl_cb) override;
+    Return<void>      getParameterList(getParameterList_cb _hidl_cb) override;
+    Return<void>      getIntParameterRange(CameraParam id,
+                                           getIntParameterRange_cb _hidl_cb) override;
+    Return<void>      setIntParameter(CameraParam id, int32_t value,
+                                      setIntParameter_cb _hidl_cb) override;
+    Return<void>      getIntParameter(CameraParam id,
+                                      getIntParameter_cb _hidl_cb) override;
 
-    // Implementation details
-    EvsCamera(const char *id);
+    static sp<EvsCamera> Create(const char *deviceName);
+    static sp<EvsCamera> Create(const char *deviceName,
+                                unique_ptr<ConfigManager::CameraInfo> &camInfo,
+                                const Stream *streamCfg = nullptr);
+    EvsCamera(const EvsCamera&) = delete;
+    EvsCamera& operator=(const EvsCamera&) = delete;
+
     virtual ~EvsCamera() override;
     void forceShutdown();   // This gets called if another caller "steals" ownership of the camera
 
@@ -79,7 +91,10 @@
     static const char kCameraName_Backup[];
 
 private:
+    EvsCamera(const char *id,
+              unique_ptr<ConfigManager::CameraInfo> &camInfo);
     // These three functions are expected to be called while mAccessLock is held
+    //
     bool setAvailableFrames_Locked(unsigned bufferCount);
     unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
     unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
@@ -124,6 +139,9 @@
 
     // Synchronization necessary to deconflict mCaptureThread from the main service thread
     std::mutex mAccessLock;
+
+    // Static camera module information
+    unique_ptr<ConfigManager::CameraInfo> &mCameraInfo;
 };
 
 } // namespace implementation
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
index b324907..a010729 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -33,6 +33,7 @@
 //        constructs a new instance for each client.
 std::list<EvsEnumerator::CameraRecord>   EvsEnumerator::sCameraList;
 wp<EvsDisplay>                           EvsEnumerator::sActiveDisplay;
+unique_ptr<ConfigManager>                EvsEnumerator::sConfigManager;
 
 
 EvsEnumerator::EvsEnumerator() {
@@ -40,9 +41,11 @@
 
     // Add sample camera data to our list of cameras
     // In a real driver, this would be expected to can the available hardware
-    sCameraList.emplace_back(EvsCamera::kCameraName_Backup);
-    sCameraList.emplace_back("LaneView");
-    sCameraList.emplace_back("right turn");
+    sConfigManager =
+        ConfigManager::Create("/etc/automotive/evs/evs_sample_configuration.xml");
+    for (auto v : sConfigManager->getCameraList()) {
+        sCameraList.emplace_back(v.c_str());
+    }
 }
 
 
@@ -57,7 +60,7 @@
     std::vector<CameraDesc_1_0> descriptions;
     descriptions.reserve(numCameras);
     for (const auto& cam : sCameraList) {
-        descriptions.push_back( cam.desc );
+        descriptions.push_back( cam.desc.v1 );
     }
 
     // Encapsulate our camera descriptions in the HIDL vec type
@@ -78,7 +81,7 @@
     // Find the named camera
     CameraRecord *pRecord = nullptr;
     for (auto &&cam : sCameraList) {
-        if (cam.desc.cameraId == cameraId) {
+        if (cam.desc.v1.cameraId == cameraId) {
             // Found a match!
             pRecord = &cam;
             break;
@@ -99,7 +102,12 @@
     }
 
     // Construct a camera instance for the caller
-    pActiveCamera = new EvsCamera(cameraId.c_str());
+    if (sConfigManager == nullptr) {
+        pActiveCamera = EvsCamera::Create(cameraId.c_str());
+    } else {
+        pActiveCamera = EvsCamera::Create(cameraId.c_str(),
+                                          sConfigManager->getCameraInfo(cameraId));
+    }
     pRecord->activeInstance = pActiveCamera;
     if (pActiveCamera == nullptr) {
         ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
@@ -120,15 +128,15 @@
 
     // Get the camera id so we can find it in our list
     std::string cameraId;
-    pCamera_1_1->getCameraInfo([&cameraId](CameraDesc desc) {
-                               cameraId = desc.cameraId;
+    pCamera_1_1->getCameraInfo_1_1([&cameraId](CameraDesc desc) {
+                               cameraId = desc.v1.cameraId;
                            }
     );
 
     // Find the named camera
     CameraRecord *pRecord = nullptr;
     for (auto &&cam : sCameraList) {
-        if (cam.desc.cameraId == cameraId) {
+        if (cam.desc.v1.cameraId == cameraId) {
             // Found a match!
             pRecord = &cam;
             break;
@@ -209,6 +217,89 @@
 }
 
 
+// Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+Return<void> EvsEnumerator::getCameraList_1_1(getCameraList_1_1_cb _hidl_cb)  {
+    ALOGD("getCameraList");
+
+    const unsigned numCameras = sCameraList.size();
+
+    // Build up a packed array of CameraDesc for return
+    // NOTE:  Only has to live until the callback returns
+    std::vector<CameraDesc_1_1> descriptions;
+    descriptions.reserve(numCameras);
+    for (const auto& cam : sCameraList) {
+        descriptions.push_back( cam.desc );
+    }
+
+    // Encapsulate our camera descriptions in the HIDL vec type
+    hidl_vec<CameraDesc_1_1> hidlCameras(descriptions);
+
+    // Send back the results
+    ALOGD("reporting %zu cameras available", hidlCameras.size());
+    _hidl_cb(hidlCameras);
+
+    // HIDL convention says we return Void if we sent our result back via callback
+    return Void();
+}
+
+Return<sp<IEvsCamera_1_1>>
+EvsEnumerator::openCamera_1_1(const hidl_string& cameraId,
+                              const Stream& streamCfg) {
+    // Find the named camera
+    CameraRecord *pRecord = nullptr;
+    for (auto &&cam : sCameraList) {
+        if (cam.desc.v1.cameraId == cameraId) {
+            // Found a match!
+            pRecord = &cam;
+            break;
+        }
+    }
+
+    // Is this a recognized camera id?
+    if (!pRecord) {
+        ALOGE("Requested camera %s not found", cameraId.c_str());
+        return nullptr;
+    }
+
+    // Has this camera already been instantiated by another caller?
+    sp<EvsCamera> pActiveCamera = pRecord->activeInstance.promote();
+    if (pActiveCamera != nullptr) {
+        ALOGW("Killing previous camera because of new caller");
+        closeCamera(pActiveCamera);
+    }
+
+    // Construct a camera instance for the caller
+    if (sConfigManager == nullptr) {
+        pActiveCamera = EvsCamera::Create(cameraId.c_str());
+    } else {
+        pActiveCamera = EvsCamera::Create(cameraId.c_str(),
+                                          sConfigManager->getCameraInfo(cameraId),
+                                          &streamCfg);
+    }
+
+    pRecord->activeInstance = pActiveCamera;
+    if (pActiveCamera == nullptr) {
+        ALOGE("Failed to allocate new EvsCamera object for %s\n", cameraId.c_str());
+    }
+
+    return pActiveCamera;
+}
+
+
+EvsEnumerator::CameraRecord* EvsEnumerator::findCameraById(const std::string& cameraId) {
+    // Find the named camera
+    CameraRecord *pRecord = nullptr;
+    for (auto &&cam : sCameraList) {
+        if (cam.desc.v1.cameraId == cameraId) {
+            // Found a match!
+            pRecord = &cam;
+            break;
+        }
+    }
+
+    return pRecord;
+}
+
 } // namespace implementation
 } // namespace V1_1
 } // namespace evs
diff --git a/automotive/evs/1.1/default/EvsEnumerator.h b/automotive/evs/1.1/default/EvsEnumerator.h
index 11c2170..475ec76 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.h
+++ b/automotive/evs/1.1/default/EvsEnumerator.h
@@ -17,18 +17,20 @@
 #ifndef ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
 #define ANDROID_HARDWARE_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
 
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
 
 #include <list>
 
+#include "ConfigManager.h"
+
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
 using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
 using ::android::hardware::automotive::evs::V1_0::DisplayState;
-using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
 using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
 using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
 using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
 
 
 namespace android {
@@ -53,6 +55,11 @@
     Return<void>                closeDisplay(const ::android::sp<IEvsDisplay>& display)  override;
     Return<DisplayState>        getDisplayState()  override;
 
+    // Methods from ::android::hardware::automotive::evs::V1_1::IEvsEnumerator follow.
+    Return<void> getCameraList_1_1(getCameraList_1_1_cb _hidl_cb)  override;
+    Return<sp<IEvsCamera_1_1>>  openCamera_1_1(const hidl_string& cameraId,
+                                               const Stream& streamCfg) override;
+
     // Implementation details
     EvsEnumerator();
 
@@ -61,14 +68,20 @@
     //        That is to say, this is effectively a singleton despite the fact that HIDL
     //        constructs a new instance for each client.
     struct CameraRecord {
-        CameraDesc_1_0      desc;
+        CameraDesc_1_1      desc;
         wp<EvsCamera>       activeInstance;
 
-        CameraRecord(const char *cameraId) : desc() { desc.cameraId = cameraId; }
+        CameraRecord(const char *cameraId) : desc() { desc.v1.cameraId = cameraId; }
     };
-    static std::list<CameraRecord> sCameraList;
 
-    static wp<EvsDisplay>          sActiveDisplay; // Weak pointer. Object destructs if client dies.
+    static CameraRecord* findCameraById(const std::string& cameraId);
+
+    static std::list<CameraRecord>   sCameraList;
+
+    // Weak pointer. Object destructs if client dies.
+    static wp<EvsDisplay>            sActiveDisplay;
+
+    static unique_ptr<ConfigManager> sConfigManager;
 };
 
 } // namespace implementation
diff --git a/automotive/evs/1.1/default/resources/evs_default_configuration.xml b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
new file mode 100644
index 0000000..692102e
--- /dev/null
+++ b/automotive/evs/1.1/default/resources/evs_default_configuration.xml
@@ -0,0 +1,68 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Exterior View System Example Configuration
+
+     Android Automotive axes are used to define coordinates.
+     See https://source.android.com/devices/sensors/sensor-types#auto_axes
+
+     Use evs_configuration.dtd with xmllint tool, to validate XML configuration file
+-->
+
+<configuration>
+    <!-- system configuration -->
+    <system>
+        <!-- number of cameras available to EVS -->
+        <num_cameras value='1'/>
+    </system>
+
+    <!-- camera device information -->
+    <camera>
+        <!-- camera device starts -->
+        <device id='/dev/video1' position='rear'>
+            <caps>
+                <!-- list of supported controls -->
+                <supported_controls>
+                    <control name='BRIGHTNESS' min='0' max='255'/>
+                    <control name='CONTRAST' min='0' max='255'/>
+                </supported_controls>
+
+                <stream id='0' width='640'  height='360'  format='RGBA_8888' framerate='30'/>
+            </caps>
+
+            <!-- list of parameters -->
+            <characteristics>
+                <!-- Camera intrinsic calibration matrix. See
+                     https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+                -->
+                <parameter
+                    name='LENS_INTRINSIC_CALIBRATION'
+                    type='float'
+                    size='5'
+                    value='0.0,0.0,0.0,0.0,0.0'
+                />
+            </characteristics>
+        </device>
+    </camera>
+    <display>
+        <device id='display0' position='driver'>
+            <caps>
+                <!-- list of supported inpu stream configurations -->
+                <stream id='0' width='1280' height='720' format='RGBA_8888' framerate='30'/>
+            </caps>
+        </device>
+    </display>
+</configuration>
+
diff --git a/automotive/evs/1.1/default/service.cpp b/automotive/evs/1.1/default/service.cpp
index 128a14a..5135864 100644
--- a/automotive/evs/1.1/default/service.cpp
+++ b/automotive/evs/1.1/default/service.cpp
@@ -33,7 +33,7 @@
 using android::hardware::joinRpcThreadpool;
 
 // Generated HIDL files
-using android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using android::hardware::automotive::evs::V1_1::IEvsEnumerator;
 using android::hardware::automotive::evs::V1_0::IEvsDisplay;
 
 // The namespace in which all our implementation code lives
diff --git a/automotive/evs/1.1/types.hal b/automotive/evs/1.1/types.hal
index 2c6b2ed..dcb2abb 100644
--- a/automotive/evs/1.1/types.hal
+++ b/automotive/evs/1.1/types.hal
@@ -21,6 +21,22 @@
 import @1.0::DisplayState;
 import @1.0::EvsResult;
 import android.hardware.graphics.common@1.2::HardwareBuffer;
+import android.hardware.camera.device@3.2::CameraMetadata;
+
+/**
+ * Structure describing the basic properties of an EVS camera, extended from its
+ * v1.0 declaration.
+ *
+ * The HAL is responsible for filling out this structure for each
+ * EVS camera in the system.
+ */
+struct CameraDesc {
+    @1.0::CameraDesc v1;
+    /**
+     * Store camera metadata such as lens characteristics.
+     */
+    CameraMetadata metadata;
+};
 
 /**
  * Structure representing an image buffer through our APIs
@@ -50,7 +66,7 @@
 /**
  * Types of informative streaming events
  */
-enum InfoEventType : uint32_t {
+enum EvsEventType : uint32_t {
     /**
      * Video stream is started
      */
@@ -81,11 +97,11 @@
 /**
  * Structure that describes informative events occurred during EVS is streaming
  */
-struct InfoEventDesc {
+struct EvsEvent {
     /**
      * Type of an informative event
      */
-    InfoEventType aType;
+    EvsEventType aType;
     /**
      * Possible additional information
      */
@@ -93,20 +109,6 @@
 };
 
 /**
- * EVS event definition
- */
-safe_union EvsEvent {
-    /**
-     * A buffer descriptor of an image frame
-     */
-    BufferDesc buffer;
-    /**
-     * General streaming events
-     */
-    InfoEventDesc info;
-};
-
-/**
  * EVS Camera Parameter
  */
 enum CameraParam : uint32_t {
@@ -127,14 +129,6 @@
      */
     GAIN,
     /**
-     * Mirror the image horizontally
-     */
-    HFLIP,
-    /**
-     * Mirror the image vertically
-     */
-    VFLIP,
-    /**
      * Automatic Whitebalance
      */
     AUTO_WHITE_BALANCE,
@@ -156,11 +150,6 @@
      */
     ABSOLUTE_EXPOSURE,
     /**
-     * When AEC is running in either auto or aperture priority, this parameter
-     * sets whether a frame rate varies.
-     */
-    AUTO_EXPOSURE_PRIORITY,
-    /**
      * Set the focal point of the camera to the specified position.  This
      * parameter may not be effective when auto focus is enabled.
      */
diff --git a/automotive/evs/1.1/vts/functional/Android.bp b/automotive/evs/1.1/vts/functional/Android.bp
index 55c50a4..4753933 100644
--- a/automotive/evs/1.1/vts/functional/Android.bp
+++ b/automotive/evs/1.1/vts/functional/Android.bp
@@ -23,6 +23,7 @@
     defaults: ["VtsHalTargetTestDefaults"],
     shared_libs: [
         "libui",
+        "libcamera_metadata",
     ],
     static_libs: [
         "android.hardware.automotive.evs@1.0",
@@ -31,6 +32,7 @@
         "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.common@1.2",
+        "android.hardware.camera.device@3.2",
     ],
     test_suites: ["general-tests"],
     cflags: [
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
index 1627689..6d53652 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -138,93 +138,93 @@
 }
 
 
-Return<void> FrameHandler::notifyEvent(const EvsEvent& event) {
-    // Local flag we use to keep track of when the stream is stopping
-    auto type = event.getDiscriminator();
-    if (type == EvsEvent::hidl_discriminator::info) {
-        mLock.lock();
-        mLatestEventDesc = event.info();
-        if (mLatestEventDesc.aType == InfoEventType::STREAM_STOPPED) {
-            // Signal that the last frame has been received and the stream is stopped
-            mRunning = false;
-        } else if (mLatestEventDesc.aType == InfoEventType::PARAMETER_CHANGED) {
-            ALOGD("Camera parameter 0x%X is changed to 0x%X",
-                  mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]);
+Return<void> FrameHandler::deliverFrame_1_1(const BufferDesc_1_1& bufDesc) {
+    const AHardwareBuffer_Desc* pDesc =
+        reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
+    ALOGD("Received a frame from the camera (%p)",
+          bufDesc.buffer.nativeHandle.getNativeHandle());
+
+    // Store a dimension of a received frame.
+    mFrameWidth = pDesc->width;
+    mFrameHeight = pDesc->height;
+
+    // If we were given an opened display at construction time, then send the received
+    // image back down the camera.
+    if (mDisplay.get()) {
+        // Get the output buffer we'll use to display the imagery
+        BufferDesc_1_0 tgtBuffer = {};
+        mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
+                                      tgtBuffer = buff;
+                                  }
+        );
+
+        if (tgtBuffer.memHandle == nullptr) {
+            printf("Didn't get target buffer - frame lost\n");
+            ALOGE("Didn't get requested output buffer -- skipping this frame.");
         } else {
-            ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
-        }
-        mLock.unlock();
-        mEventSignal.notify_all();
-    } else {
-        auto bufDesc = event.buffer();
-        const AHardwareBuffer_Desc* pDesc =
-            reinterpret_cast<const AHardwareBuffer_Desc *>(&bufDesc.buffer.description);
-        ALOGD("Received a frame from the camera (%p)",
-              bufDesc.buffer.nativeHandle.getNativeHandle());
+            // Copy the contents of the of buffer.memHandle into tgtBuffer
+            copyBufferContents(tgtBuffer, bufDesc);
 
-        // Store a dimension of a received frame.
-        mFrameWidth = pDesc->width;
-        mFrameHeight = pDesc->height;
-
-        // If we were given an opened display at construction time, then send the received
-        // image back down the camera.
-        if (mDisplay.get()) {
-            // Get the output buffer we'll use to display the imagery
-            BufferDesc_1_0 tgtBuffer = {};
-            mDisplay->getTargetBuffer([&tgtBuffer](const BufferDesc_1_0& buff) {
-                                          tgtBuffer = buff;
-                                      }
-            );
-
-            if (tgtBuffer.memHandle == nullptr) {
-                printf("Didn't get target buffer - frame lost\n");
-                ALOGE("Didn't get requested output buffer -- skipping this frame.");
+            // Send the target buffer back for display
+            Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
+            if (!result.isOk()) {
+                printf("HIDL error on display buffer (%s)- frame lost\n",
+                       result.description().c_str());
+                ALOGE("Error making the remote function call.  HIDL said %s",
+                      result.description().c_str());
+            } else if (result != EvsResult::OK) {
+                printf("Display reported error - frame lost\n");
+                ALOGE("We encountered error %d when returning a buffer to the display!",
+                      (EvsResult) result);
             } else {
-                // Copy the contents of the of buffer.memHandle into tgtBuffer
-                copyBufferContents(tgtBuffer, bufDesc);
-
-                // Send the target buffer back for display
-                Return<EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
-                if (!result.isOk()) {
-                    printf("HIDL error on display buffer (%s)- frame lost\n",
-                           result.description().c_str());
-                    ALOGE("Error making the remote function call.  HIDL said %s",
-                          result.description().c_str());
-                } else if (result != EvsResult::OK) {
-                    printf("Display reported error - frame lost\n");
-                    ALOGE("We encountered error %d when returning a buffer to the display!",
-                          (EvsResult) result);
-                } else {
-                    // Everything looks good!
-                    // Keep track so tests or watch dogs can monitor progress
-                    mLock.lock();
-                    mFramesDisplayed++;
-                    mLock.unlock();
-                }
+                // Everything looks good!
+                // Keep track so tests or watch dogs can monitor progress
+                mLock.lock();
+                mFramesDisplayed++;
+                mLock.unlock();
             }
         }
-
-
-        switch (mReturnMode) {
-        case eAutoReturn:
-            // Send the camera buffer back now that the client has seen it
-            ALOGD("Calling doneWithFrame");
-            // TODO:  Why is it that we get a HIDL crash if we pass back the cloned buffer?
-            mCamera->doneWithFrame_1_1(bufDesc);
-            break;
-        case eNoAutoReturn:
-            // Hang onto the buffer handle for now -- the client will return it explicitly later
-            mHeldBuffers.push(bufDesc);
-        }
-
-        mLock.lock();
-        ++mFramesReceived;
-        mLock.unlock();
-        mFrameSignal.notify_all();
-
-        ALOGD("Frame handling complete");
     }
 
+
+    switch (mReturnMode) {
+    case eAutoReturn:
+        // Send the camera buffer back now that the client has seen it
+        ALOGD("Calling doneWithFrame");
+        mCamera->doneWithFrame_1_1(bufDesc);
+        break;
+    case eNoAutoReturn:
+        // Hang onto the buffer handle for now -- the client will return it explicitly later
+        mHeldBuffers.push(bufDesc);
+    }
+
+    mLock.lock();
+    ++mFramesReceived;
+    mLock.unlock();
+    mFrameSignal.notify_all();
+
+    ALOGD("Frame handling complete");
+
+    return Void();
+}
+
+
+Return<void> FrameHandler::notify(const EvsEvent& event) {
+    // Local flag we use to keep track of when the stream is stopping
+    mLock.lock();
+    mLatestEventDesc = event;
+    if (mLatestEventDesc.aType == EvsEventType::STREAM_STOPPED) {
+        // Signal that the last frame has been received and the stream is stopped
+        mRunning = false;
+    } else if (mLatestEventDesc.aType == EvsEventType::PARAMETER_CHANGED) {
+        ALOGD("Camera parameter 0x%X is changed to 0x%X",
+              mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]);
+    } else {
+        ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
+    }
+    mLock.unlock();
+    mEventSignal.notify_all();
+
     return Void();
 }
 
@@ -342,18 +342,18 @@
     }
 }
 
-bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent,
-                                InfoEventDesc &eventDesc) {
+bool FrameHandler::waitForEvent(const EvsEventType aTargetEvent,
+                                EvsEvent &event) {
     // Wait until we get an expected parameter change event.
     std::unique_lock<std::mutex> lock(mLock);
     auto now = std::chrono::system_clock::now();
     bool result = mEventSignal.wait_until(lock, now + 5s,
-        [this, aTargetEvent, &eventDesc](){
+        [this, aTargetEvent, &event](){
             bool flag = mLatestEventDesc.aType == aTargetEvent;
             if (flag) {
-                eventDesc.aType = mLatestEventDesc.aType;
-                eventDesc.payload[0] = mLatestEventDesc.payload[0];
-                eventDesc.payload[1] = mLatestEventDesc.payload[1];
+                event.aType = mLatestEventDesc.aType;
+                event.payload[0] = mLatestEventDesc.payload[0];
+                event.payload[1] = mLatestEventDesc.payload[1];
             }
 
             return flag;
@@ -363,21 +363,22 @@
     return !result;
 }
 
-const char *FrameHandler::eventToString(const InfoEventType aType) {
+const char *FrameHandler::eventToString(const EvsEventType aType) {
     switch (aType) {
-        case InfoEventType::STREAM_STARTED:
+        case EvsEventType::STREAM_STARTED:
             return "STREAM_STARTED";
-        case InfoEventType::STREAM_STOPPED:
+        case EvsEventType::STREAM_STOPPED:
             return "STREAM_STOPPED";
-        case InfoEventType::FRAME_DROPPED:
+        case EvsEventType::FRAME_DROPPED:
             return "FRAME_DROPPED";
-        case InfoEventType::TIMEOUT:
+        case EvsEventType::TIMEOUT:
             return "TIMEOUT";
-        case InfoEventType::PARAMETER_CHANGED:
+        case EvsEventType::PARAMETER_CHANGED:
             return "PARAMETER_CHANGED";
-        case InfoEventType::MASTER_RELEASED:
+        case EvsEventType::MASTER_RELEASED:
             return "MASTER_RELEASED";
         default:
             return "Unknown";
     }
 }
+
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
index 7f87cb4..e5f1b8f 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.h
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -33,7 +33,6 @@
 using ::android::sp;
 using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
 using ::android::hardware::automotive::evs::V1_0::EvsResult;
-using ::android::hardware::automotive::evs::V1_0::CameraDesc;
 using BufferDesc_1_0 = ::android::hardware::automotive::evs::V1_0::BufferDesc;
 using BufferDesc_1_1 = ::android::hardware::automotive::evs::V1_1::BufferDesc;
 
@@ -56,6 +55,13 @@
     FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
                  android::sp <IEvsDisplay> pDisplay = nullptr,
                  BufferControlFlag mode = eAutoReturn);
+    virtual ~FrameHandler() {
+        if (mCamera != nullptr) {
+            /* shutdown a camera explicitly */
+            shutdown();
+        }
+    }
+
     void shutdown();
 
     bool startStream();
@@ -67,19 +73,22 @@
     bool isRunning();
 
     void waitForFrameCount(unsigned frameCount);
-    bool waitForEvent(const InfoEventType aTargetEvent,
-                            InfoEventDesc &eventDesc);
+    bool waitForEvent(const EvsEventType aTargetEvent,
+                            EvsEvent &eventDesc);
     void getFramesCounters(unsigned* received, unsigned* displayed);
     void getFrameDimension(unsigned* width, unsigned* height);
 
 private:
-    // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+    // Implementation for ::android::hardware::automotive::evs::V1_0::IEvsCameraStream
     Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
-    Return<void> notifyEvent(const EvsEvent& event) override;
+
+    // Implementation for ::android::hardware::automotive::evs::V1_1::IEvsCameraStream
+    Return<void> deliverFrame_1_1(const BufferDesc_1_1& buffer) override;
+    Return<void> notify(const EvsEvent& event) override;
 
     // Local implementation details
     bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer);
-    const char *eventToString(const InfoEventType aType);
+    const char *eventToString(const EvsEventType aType);
 
     // Values initialized as startup
     android::sp <IEvsCamera>    mCamera;
@@ -100,7 +109,7 @@
     unsigned                    mFramesDisplayed = 0;   // Simple counter -- rolls over eventually!
     unsigned                    mFrameWidth = 0;
     unsigned                    mFrameHeight = 0;
-    InfoEventDesc               mLatestEventDesc;
+    EvsEvent                    mLatestEventDesc;
 };
 
 
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index a6e4881..1d3fd87 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -38,8 +38,9 @@
 
 #include "FrameHandler.h"
 
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
 
 #include <hidl/HidlTransportSupport.h>
 #include <hwbinder/ProcessState.h>
@@ -50,8 +51,10 @@
 #include <android/log.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
 #include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
-#include <android/hardware/automotive/evs/1.0/IEvsEnumerator.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
 #include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <system/camera_metadata.h>
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <VtsHalHidlTargetTestEnvBase.h>
@@ -64,13 +67,28 @@
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::sp;
-using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using ::android::hardware::camera::device::V3_2::Stream;
 using ::android::hardware::automotive::evs::V1_0::DisplayDesc;
 using ::android::hardware::automotive::evs::V1_0::DisplayState;
-using ::android::hardware::automotive::evs::V1_0::IEvsEnumerator;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
 using IEvsCamera_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsCamera;
 using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera;
 
+/*
+ * Plese note that this is different from what is defined in
+ * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
+ * field to store a framerate.
+ */
+const size_t kStreamCfgSz = 5;
+typedef struct {
+    int32_t width;
+    int32_t height;
+    int32_t format;
+    int32_t direction;
+    int32_t framerate;
+} RawStreamConfig;
+
+
 // Test environment for Evs HIDL HAL.
 class EvsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
    public:
@@ -107,15 +125,16 @@
         assert(pEnumerator != nullptr);
 
         // Get the camera list
-        pEnumerator->getCameraList([this](hidl_vec <CameraDesc> cameraList) {
-                                       ALOGI("Camera list callback received %zu cameras",
-                                             cameraList.size());
-                                       cameraInfo.reserve(cameraList.size());
-                                       for (auto&& cam: cameraList) {
-                                           ALOGI("Found camera %s", cam.cameraId.c_str());
-                                           cameraInfo.push_back(cam);
-                                       }
-                                   }
+        pEnumerator->getCameraList_1_1(
+            [this](hidl_vec <CameraDesc> cameraList) {
+                ALOGI("Camera list callback received %zu cameras",
+                      cameraList.size());
+                cameraInfo.reserve(cameraList.size());
+                for (auto&& cam: cameraList) {
+                    ALOGI("Found camera %s", cam.v1.cameraId.c_str());
+                    cameraInfo.push_back(cam);
+                }
+            }
         );
 
         // We insist on at least one camera for EVS to pass any camera tests
@@ -143,19 +162,23 @@
     // Get the camera list
     loadCameraList();
 
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
     // Open and close each camera twice
     for (auto&& cam: cameraInfo) {
         for (int pass = 0; pass < 2; pass++) {
             sp<IEvsCamera_1_1> pCam =
-                IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+                IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
                 .withDefault(nullptr);
             ASSERT_NE(pCam, nullptr);
 
             // Verify that this camera self-identifies correctly
-            pCam->getCameraInfo([&cam](CameraDesc desc) {
-                                    ALOGD("Found camera %s", desc.cameraId.c_str());
-                                    EXPECT_EQ(cam.cameraId, desc.cameraId);
-                                }
+            pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
+                                        ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+                                        EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+                                    }
             );
 
             // Explicitly close the camera so resources are released right away
@@ -177,22 +200,26 @@
     // Get the camera list
     loadCameraList();
 
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
     // Open and close each camera twice
     for (auto&& cam: cameraInfo) {
         sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
         // Verify that this camera self-identifies correctly
-        pCam->getCameraInfo([&cam](CameraDesc desc) {
-                                ALOGD("Found camera %s", desc.cameraId.c_str());
-                                EXPECT_EQ(cam.cameraId, desc.cameraId);
-                            }
+        pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
+                                    ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+                                    EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+                                }
         );
 
         sp<IEvsCamera_1_1> pCam2 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, pCam2);
         ASSERT_NE(pCam2, nullptr);
@@ -210,10 +237,10 @@
         pEnumerator->closeCamera(pCam);
 
         // Verify that the second camera instance self-identifies correctly
-        pCam2->getCameraInfo([&cam](CameraDesc desc) {
-                                 ALOGD("Found camera %s", desc.cameraId.c_str());
-                                 EXPECT_EQ(cam.cameraId, desc.cameraId);
-                             }
+        pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) {
+                                     ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+                                     EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
+                                 }
         );
 
         // Close the second camera instance
@@ -235,10 +262,14 @@
     // Get the camera list
     loadCameraList();
 
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
         sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
@@ -303,11 +334,15 @@
     // Get the camera list
     loadCameraList();
 
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
 
         sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
@@ -371,6 +406,10 @@
     // Get the camera list
     loadCameraList();
 
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
     // Request exclusive access to the EVS display
     sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
     ASSERT_NE(pDisplay, nullptr);
@@ -378,7 +417,7 @@
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
         sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
@@ -439,16 +478,20 @@
     // Get the camera list
     loadCameraList();
 
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
         // Create two camera clients.
         sp<IEvsCamera_1_1> pCam0 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam0, nullptr);
 
         sp<IEvsCamera_1_1> pCam1 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam1, nullptr);
 
@@ -486,7 +529,6 @@
         nsecs_t runTime = end - firstFrame;
         float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
         float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
-        printf("Measured camera rate %3.2f fps and %3.2f fps\n", framesPerSecond0, framesPerSecond1);
         ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
         EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
         EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
@@ -526,14 +568,33 @@
     // Get the camera list
     loadCameraList();
 
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
     // Test each reported camera
+    Return<EvsResult> result = EvsResult::OK;
     for (auto&& cam: cameraInfo) {
         // Create a camera client
         sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam, nullptr);
 
+        // Get the parameter list
+        std::vector<CameraParam> cmds;
+        pCam->getParameterList([&cmds](hidl_vec<CameraParam> cmdList) {
+                cmds.reserve(cmdList.size());
+                for (auto &&cmd : cmdList) {
+                    cmds.push_back(cmd);
+                }
+            }
+        );
+
+        if (cmds.size() < 1) {
+            continue;
+        }
+
         // Set up per-client frame receiver objects which will fire up its own thread
         sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
                                                          nullptr,
@@ -547,83 +608,70 @@
         // Ensure the stream starts
         frameHandler->waitForFrameCount(1);
 
-        // Try to program few parameters
-        EvsResult result = EvsResult::OK;
-        int32_t val0 = 100;
-        int32_t val1 = 0;
-
         result = pCam->setMaster();
-        ASSERT_TRUE(result == EvsResult::OK);
+        ASSERT_EQ(EvsResult::OK, result);
 
-        pCam->setParameter(CameraParam::BRIGHTNESS, val0,
-                           [&result, &val1](auto status, auto effectiveValue) {
-                               result = status;
-                               val1 = effectiveValue;
-                           });
-        ASSERT_TRUE(result == EvsResult::OK ||
-                    result == EvsResult::INVALID_ARG);
+        for (auto &cmd : cmds) {
+            // Get a valid parameter value range
+            int32_t minVal, maxVal, step;
+            pCam->getIntParameterRange(
+                cmd,
+                [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+                    minVal = val0;
+                    maxVal = val1;
+                    step   = val2;
+                }
+            );
 
-        if (result == EvsResult::OK) {
-            pCam->getParameter(CameraParam::BRIGHTNESS,
+            EvsResult result = EvsResult::OK;
+            if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+                // Try to turn off auto-focus
+                int32_t val1 = 0;
+                pCam->getIntParameter(CameraParam::AUTO_FOCUS,
+                                   [&result, &val1](auto status, auto value) {
+                                       result = status;
+                                       if (status == EvsResult::OK) {
+                                          val1 = value;
+                                       }
+                                   });
+                if (val1 != 0) {
+                    pCam->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                       [&result, &val1](auto status, auto effectiveValue) {
+                                           result = status;
+                                           val1 = effectiveValue;
+                                       });
+                    ASSERT_EQ(EvsResult::OK, result);
+                    ASSERT_EQ(val1, 0);
+                }
+            }
+
+            // Try to program a parameter with a random value [minVal, maxVal]
+            int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
+            int32_t val1 = 0;
+
+            // Rounding down
+            val0 = val0 - (val0 % step);
+            pCam->setIntParameter(cmd, val0,
+                               [&result, &val1](auto status, auto effectiveValue) {
+                                   result = status;
+                                   val1 = effectiveValue;
+                               });
+
+            ASSERT_EQ(EvsResult::OK, result);
+
+            pCam->getIntParameter(cmd,
                                [&result, &val1](auto status, auto value) {
                                    result = status;
                                    if (status == EvsResult::OK) {
                                       val1 = value;
                                    }
                                });
-            ASSERT_TRUE(result == EvsResult::OK ||
-                        result == EvsResult::INVALID_ARG);
-            ASSERT_EQ(val0, val1) << "Values are not matched.";
-        }
-
-        val0 = 80;
-        val1 = 0;
-        pCam->setParameter(CameraParam::CONTRAST, val0,
-                           [&result, &val1](auto status, auto effectiveValue) {
-                               result = status;
-                               val1 = effectiveValue;
-                           });
-        ASSERT_TRUE(result == EvsResult::OK ||
-                    result == EvsResult::INVALID_ARG);
-
-        if (result == EvsResult::OK) {
-            pCam->getParameter(CameraParam::CONTRAST,
-                               [&result, &val1](auto status, auto value) {
-                                   result = status;
-                                   if (status == EvsResult::OK) {
-                                      val1 = value;
-                                   }
-                               });
-            ASSERT_TRUE(result == EvsResult::OK ||
-                        result == EvsResult::INVALID_ARG);
-            ASSERT_EQ(val0, val1) << "Values are not matched.";
-        }
-
-        val0 = 300;
-        val1 = 0;
-        pCam->setParameter(CameraParam::ABSOLUTE_ZOOM, val0,
-                           [&result, &val1](auto status, auto effectiveValue) {
-                               result = status;
-                               val1 = effectiveValue;
-                           });
-        ASSERT_TRUE(result == EvsResult::OK ||
-                    result == EvsResult::INVALID_ARG);
-
-        if (result == EvsResult::OK) {
-            pCam->getParameter(CameraParam::ABSOLUTE_ZOOM,
-                               [&result, &val1](auto status, auto value) {
-                                   result = status;
-                                   if (status == EvsResult::OK) {
-                                      val1 = value;
-                                   }
-                               });
-            ASSERT_TRUE(result == EvsResult::OK ||
-                        result == EvsResult::INVALID_ARG);
+            ASSERT_EQ(EvsResult::OK, result);
             ASSERT_EQ(val0, val1) << "Values are not matched.";
         }
 
         result = pCam->unsetMaster();
-        ASSERT_TRUE(result == EvsResult::OK);
+        ASSERT_EQ(EvsResult::OK, result);
 
         // Shutdown
         frameHandler->shutdown();
@@ -650,15 +698,19 @@
     // Get the camera list
     loadCameraList();
 
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
         // Create two camera clients.
         sp<IEvsCamera_1_1> pCamMaster =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCamMaster, nullptr);
         sp<IEvsCamera_1_1> pCamNonMaster =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCamNonMaster, nullptr);
 
@@ -698,15 +750,15 @@
 
         // Non-master client expects to receive a master role relesed
         // notification.
-        InfoEventDesc aNotification = {};
+        EvsEvent aNotification = {};
 
         // Release a master role.
         pCamMaster->unsetMaster();
 
         // Verify a change notification.
-        frameHandlerNonMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
-        ASSERT_EQ(InfoEventType::MASTER_RELEASED,
-                  static_cast<InfoEventType>(aNotification.aType));
+        frameHandlerNonMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+        ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+                  static_cast<EvsEventType>(aNotification.aType));
 
         // Non-master becomes a master.
         result = pCamNonMaster->setMaster();
@@ -720,9 +772,9 @@
         frameHandlerNonMaster->shutdown();
 
         // Verify a change notification.
-        frameHandlerMaster->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
-        ASSERT_EQ(InfoEventType::MASTER_RELEASED,
-                  static_cast<InfoEventType>(aNotification.aType));
+        frameHandlerMaster->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+        ASSERT_EQ(EvsEventType::MASTER_RELEASED,
+                  static_cast<EvsEventType>(aNotification.aType));
 
         // Closing another stream.
         frameHandlerMaster->shutdown();
@@ -752,18 +804,46 @@
     // Get the camera list
     loadCameraList();
 
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
         // Create two camera clients.
         sp<IEvsCamera_1_1> pCamMaster =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCamMaster, nullptr);
         sp<IEvsCamera_1_1> pCamNonMaster =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCamNonMaster, nullptr);
 
+        // Get the parameter list
+        std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
+        pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
+                camMasterCmds.reserve(cmdList.size());
+                for (auto &&cmd : cmdList) {
+                    camMasterCmds.push_back(cmd);
+                }
+            }
+        );
+
+        pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec<CameraParam> cmdList) {
+                camNonMasterCmds.reserve(cmdList.size());
+                for (auto &&cmd : cmdList) {
+                    camNonMasterCmds.push_back(cmd);
+                }
+            }
+        );
+
+        if (camMasterCmds.size() < 1 ||
+            camNonMasterCmds.size() < 1) {
+            // Skip a camera device if it does not support any parameter.
+            continue;
+        }
+
         // Set up per-client frame receiver objects which will fire up its own thread
         sp<FrameHandler> frameHandlerMaster =
             new FrameHandler(pCamMaster, cam,
@@ -778,11 +858,11 @@
 
         // Set one client as the master
         EvsResult result = pCamMaster->setMaster();
-        ASSERT_TRUE(result == EvsResult::OK);
+        ASSERT_EQ(EvsResult::OK, result);
 
         // Try to set another client as the master.
         result = pCamNonMaster->setMaster();
-        ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+        ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
 
         // Start the camera's video stream via a master client.
         bool startResult = frameHandlerMaster->startStream();
@@ -798,131 +878,168 @@
         // Ensure the stream starts
         frameHandlerNonMaster->waitForFrameCount(1);
 
-        // Try to program CameraParam::BRIGHTNESS
-        int32_t val0 = 100;
+        int32_t val0 = 0;
         int32_t val1 = 0;
+        for (auto &cmd : camMasterCmds) {
+            // Get a valid parameter value range
+            int32_t minVal, maxVal, step;
+            pCamMaster->getIntParameterRange(
+                cmd,
+                [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+                    minVal = val0;
+                    maxVal = val1;
+                    step   = val2;
+                }
+            );
 
-        pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0,
-                                 [&result, &val1](auto status, auto effectiveValue) {
-                                     result = status;
-                                     val1 = effectiveValue;
-                                 });
-        ASSERT_TRUE(result == EvsResult::OK ||            // Succeeded to program
-                    result == EvsResult::INVALID_ARG);    // Camera parameter is not supported
+            EvsResult result = EvsResult::OK;
+            if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+                // Try to turn off auto-focus
+                int32_t val1 = 1;
+                pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &val1](auto status, auto effectiveValue) {
+                                       result = status;
+                                       val1 = effectiveValue;
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                ASSERT_EQ(val1, 0);
+            }
 
-        // Non-master client expects to receive a parameter change notification
-        // whenever a master client adjusts it.
-        InfoEventDesc aNotification = {};
+            // Try to program a parameter
+            val0 = minVal + (std::rand() % (maxVal - minVal));
 
-        pCamMaster->getParameter(CameraParam::BRIGHTNESS,
-                                 [&result, &val1](auto status, auto value) {
-                                     result = status;
-                                     if (status == EvsResult::OK) {
-                                        val1 = value;
-                                     }
-                                 });
-        ASSERT_TRUE(result == EvsResult::OK ||            // Succeeded to program
-                    result == EvsResult::INVALID_ARG);    // Camera parameter is not supported
-        if (result == EvsResult::OK) {
-            ASSERT_EQ(val0, val1) << "Values are not matched.";
+            // Rounding down
+            val0 = val0 - (val0 % step);
+            pCamMaster->setIntParameter(cmd, val0,
+                                     [&result, &val1](auto status, auto effectiveValue) {
+                                         result = status;
+                                         val1 = effectiveValue;
+                                     });
+            ASSERT_EQ(EvsResult::OK, result);
 
-            // Verify a change notification
-            frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
-            ASSERT_EQ(InfoEventType::PARAMETER_CHANGED,
-                      static_cast<InfoEventType>(aNotification.aType));
-            ASSERT_EQ(CameraParam::BRIGHTNESS,
-                      static_cast<CameraParam>(aNotification.payload[0]));
-            ASSERT_EQ(val1,
-                      static_cast<int32_t>(aNotification.payload[1]));
-        }
+            // Wait a moment
+            sleep(1);
 
-        // Try to program CameraParam::CONTRAST
-        val0 = 80;
-        val1 = 0;
-        pCamMaster->setParameter(CameraParam::CONTRAST, val0,
-                                 [&result, &val1](auto status, auto effectiveValue) {
-                                     result = status;
-                                     val1 = effectiveValue;
-                                 });
-        ASSERT_TRUE(result == EvsResult::OK ||            // Succeeded to program
-                    result == EvsResult::INVALID_ARG);    // Camera parameter is not supported
+            // Non-master client expects to receive a parameter change notification
+            // whenever a master client adjusts it.
+            EvsEvent aNotification = {};
 
-        if (result == EvsResult::OK) {
-            pCamMaster->getParameter(CameraParam::CONTRAST,
+            pCamMaster->getIntParameter(cmd,
                                      [&result, &val1](auto status, auto value) {
                                          result = status;
                                          if (status == EvsResult::OK) {
                                             val1 = value;
                                          }
                                      });
-            ASSERT_TRUE(result == EvsResult::OK);
+            ASSERT_EQ(EvsResult::OK, result);
             ASSERT_EQ(val0, val1) << "Values are not matched.";
 
-
             // Verify a change notification
-            frameHandlerNonMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
-            ASSERT_EQ(InfoEventType::PARAMETER_CHANGED,
-                      static_cast<InfoEventType>(aNotification.aType));
-            ASSERT_EQ(CameraParam::CONTRAST,
+            frameHandlerNonMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification.aType));
+            ASSERT_EQ(cmd,
                       static_cast<CameraParam>(aNotification.payload[0]));
             ASSERT_EQ(val1,
                       static_cast<int32_t>(aNotification.payload[1]));
         }
 
         // Try to adjust a parameter via non-master client
-        pCamNonMaster->setParameter(CameraParam::CONTRAST, val0,
+        pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
                                     [&result, &val1](auto status, auto effectiveValue) {
                                         result = status;
                                         val1 = effectiveValue;
                                     });
-        ASSERT_TRUE(result == EvsResult::INVALID_ARG);
+        ASSERT_EQ(EvsResult::INVALID_ARG, result);
 
         // Non-master client attemps to be a master
         result = pCamNonMaster->setMaster();
-        ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
+        ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
 
         // Master client retires from a master role
         result = pCamMaster->unsetMaster();
-        ASSERT_TRUE(result == EvsResult::OK);
+        ASSERT_EQ(EvsResult::OK, result);
 
         // Try to adjust a parameter after being retired
-        pCamMaster->setParameter(CameraParam::BRIGHTNESS, val0,
+        pCamMaster->setIntParameter(camMasterCmds[0], val0,
                                  [&result, &val1](auto status, auto effectiveValue) {
                                      result = status;
                                      val1 = effectiveValue;
                                  });
-        ASSERT_TRUE(result == EvsResult::INVALID_ARG);
+        ASSERT_EQ(EvsResult::INVALID_ARG, result);
 
         // Non-master client becomes a master
         result = pCamNonMaster->setMaster();
-        ASSERT_TRUE(result == EvsResult::OK);
+        ASSERT_EQ(EvsResult::OK, result);
 
         // Try to adjust a parameter via new master client
-        pCamNonMaster->setParameter(CameraParam::BRIGHTNESS, val0,
-                                    [&result, &val1](auto status, auto effectiveValue) {
-                                        result = status;
-                                        val1 = effectiveValue;
-                                    });
-        ASSERT_TRUE(result == EvsResult::OK ||            // Succeeded to program
-                    result == EvsResult::INVALID_ARG);    // Camera parameter is not supported
+        for (auto &cmd : camNonMasterCmds) {
+            // Get a valid parameter value range
+            int32_t minVal, maxVal, step;
+            pCamNonMaster->getIntParameterRange(
+                cmd,
+                [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+                    minVal = val0;
+                    maxVal = val1;
+                    step   = val2;
+                }
+            );
 
-        // Wait a moment
-        sleep(1);
+            EvsResult result = EvsResult::OK;
+            if (cmd == CameraParam::ABSOLUTE_FOCUS) {
+                // Try to turn off auto-focus
+                int32_t val1 = 1;
+                pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &val1](auto status, auto effectiveValue) {
+                                       result = status;
+                                       val1 = effectiveValue;
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                ASSERT_EQ(val1, 0);
+            }
 
-        // Verify a change notification
-        if (result == EvsResult::OK) {
-            frameHandlerMaster->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
-            ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
-                      InfoEventType::PARAMETER_CHANGED);
-            ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
-                      CameraParam::BRIGHTNESS);
+            // Try to program a parameter
+            val0 = minVal + (std::rand() % (maxVal - minVal));
+
+            // Rounding down
+            val0 = val0 - (val0 % step);
+            pCamNonMaster->setIntParameter(cmd, val0,
+                                        [&result, &val1](auto status, auto effectiveValue) {
+                                            result = status;
+                                            val1 = effectiveValue;
+                                        });
+            ASSERT_EQ(EvsResult::OK, result);
+
+            // Wait a moment
+            sleep(1);
+
+            // Non-master client expects to receive a parameter change notification
+            // whenever a master client adjusts it.
+            EvsEvent aNotification = {};
+
+            pCamNonMaster->getIntParameter(cmd,
+                                        [&result, &val1](auto status, auto value) {
+                                            result = status;
+                                            if (status == EvsResult::OK) {
+                                               val1 = value;
+                                            }
+                                        });
+            ASSERT_EQ(EvsResult::OK, result);
+            ASSERT_EQ(val0, val1) << "Values are not matched.";
+
+            // Verify a change notification
+            frameHandlerMaster->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+            ASSERT_EQ(EvsEventType::PARAMETER_CHANGED,
+                      static_cast<EvsEventType>(aNotification.aType));
+            ASSERT_EQ(cmd,
+                      static_cast<CameraParam>(aNotification.payload[0]));
             ASSERT_EQ(val1,
                       static_cast<int32_t>(aNotification.payload[1]));
         }
 
         // New master retires from a master role
         result = pCamNonMaster->unsetMaster();
-        ASSERT_TRUE(result == EvsResult::OK);
+        ASSERT_EQ(EvsResult::OK, result);
 
         // Shutdown
         frameHandlerMaster->shutdown();
@@ -943,9 +1060,18 @@
 TEST_F(EvsHidlTest, HighPriorityCameraClient) {
     ALOGI("Starting HighPriorityCameraClient test");
 
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
     // Get the camera list
     loadCameraList();
 
+    // Using null stream configuration makes EVS uses the default resolution and
+    // output format.
+    Stream nullCfg = {};
+
     // Request exclusive access to the EVS display
     sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
     ASSERT_NE(pDisplay, nullptr);
@@ -954,15 +1080,38 @@
     for (auto&& cam: cameraInfo) {
         // Create two clients
         sp<IEvsCamera_1_1> pCam0 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam0, nullptr);
 
         sp<IEvsCamera_1_1> pCam1 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
         ASSERT_NE(pCam1, nullptr);
 
+        // Get the parameter list; this test will use the first command in both
+        // lists.
+        std::vector<CameraParam> cam0Cmds, cam1Cmds;
+        pCam0->getParameterList([&cam0Cmds](hidl_vec<CameraParam> cmdList) {
+                cam0Cmds.reserve(cmdList.size());
+                for (auto &&cmd : cmdList) {
+                    cam0Cmds.push_back(cmd);
+                }
+            }
+        );
+
+        pCam1->getParameterList([&cam1Cmds](hidl_vec<CameraParam> cmdList) {
+                cam1Cmds.reserve(cmdList.size());
+                for (auto &&cmd : cmdList) {
+                    cam1Cmds.push_back(cmd);
+                }
+            }
+        );
+        if (cam0Cmds.size() < 1 || cam1Cmds.size() < 1) {
+            // Cannot execute this test.
+            return;
+        }
+
         // Set up a frame receiver object which will fire up its own thread.
         sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
                                                           pDisplay,
@@ -982,67 +1131,121 @@
         frameHandler0->waitForFrameCount(1);
         frameHandler1->waitForFrameCount(1);
 
-        // Client 1 becomes a master and programs a brightness.
+        // Client 1 becomes a master and programs a parameter.
         EvsResult result = EvsResult::OK;
-        int32_t val0 = 100;
+        // Get a valid parameter value range
+        int32_t minVal, maxVal, step;
+        pCam1->getIntParameterRange(
+            cam1Cmds[0],
+            [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
+                minVal = val0;
+                maxVal = val1;
+                step   = val2;
+            }
+        );
+
+        if (cam1Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+            // Try to turn off auto-focus
+            int32_t val1 = 0;
+            pCam1->getIntParameter(CameraParam::AUTO_FOCUS,
+                               [&result, &val1](auto status, auto value) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      val1 = value;
+                                   }
+                               });
+            if (val1 != 0) {
+                pCam1->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &val1](auto status, auto effectiveValue) {
+                                       result = status;
+                                       val1 = effectiveValue;
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                ASSERT_EQ(val1, 0);
+            }
+        }
+
+        // Try to program a parameter with a random value [minVal, maxVal]
+        int32_t val0 = minVal + (std::rand() % (maxVal - minVal));
         int32_t val1 = 0;
 
-        result = pCam1->setMaster();
-        ASSERT_TRUE(result == EvsResult::OK);
+        // Rounding down
+        val0 = val0 - (val0 % step);
 
-        pCam1->setParameter(CameraParam::BRIGHTNESS, val0,
+        result = pCam1->setMaster();
+        ASSERT_EQ(EvsResult::OK, result);
+
+        pCam1->setIntParameter(cam1Cmds[0], val0,
                             [&result, &val1](auto status, auto effectiveValue) {
                                 result = status;
                                 val1 = effectiveValue;
                             });
-        ASSERT_TRUE(result == EvsResult::OK ||
-                    result == EvsResult::INVALID_ARG);
-
+        ASSERT_EQ(EvsResult::OK, result);
 
         // Verify a change notification
-        InfoEventDesc aNotification = {};
-        if (result == EvsResult::OK) {
-            bool timeout =
-                frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
-            ASSERT_FALSE(timeout) << "Expected event does not arrive";
-            ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
-                      InfoEventType::PARAMETER_CHANGED);
-            ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
-                      CameraParam::BRIGHTNESS);
-            ASSERT_EQ(val1,
-                      static_cast<int32_t>(aNotification.payload[1]));
-        }
+        EvsEvent aNotification = {};
+        bool timeout =
+            frameHandler0->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+        ASSERT_FALSE(timeout) << "Expected event does not arrive";
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                  EvsEventType::PARAMETER_CHANGED);
+        ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+                  cam1Cmds[0]);
+        ASSERT_EQ(val1,
+                  static_cast<int32_t>(aNotification.payload[1]));
 
         // Client 0 steals a master role
         ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
 
-        frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
-        ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
-                  InfoEventType::MASTER_RELEASED);
+        frameHandler1->waitForEvent(EvsEventType::MASTER_RELEASED, aNotification);
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                  EvsEventType::MASTER_RELEASED);
 
-        // Client 0 programs a brightness
-        val0 = 50;
+        // Client 0 programs a parameter
+        val0 = minVal + (std::rand() % (maxVal - minVal));
         val1 = 0;
-        pCam0->setParameter(CameraParam::BRIGHTNESS, val0,
+
+        // Rounding down
+        val0 = val0 - (val0 % step);
+
+        if (cam0Cmds[0] == CameraParam::ABSOLUTE_FOCUS) {
+            // Try to turn off auto-focus
+            int32_t val1 = 0;
+            pCam0->getIntParameter(CameraParam::AUTO_FOCUS,
+                               [&result, &val1](auto status, auto value) {
+                                   result = status;
+                                   if (status == EvsResult::OK) {
+                                      val1 = value;
+                                   }
+                               });
+            if (val1 != 0) {
+                pCam0->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                                   [&result, &val1](auto status, auto effectiveValue) {
+                                       result = status;
+                                       val1 = effectiveValue;
+                                   });
+                ASSERT_EQ(EvsResult::OK, result);
+                ASSERT_EQ(val1, 0);
+            }
+        }
+
+        pCam0->setIntParameter(cam0Cmds[0], val0,
                             [&result, &val1](auto status, auto effectiveValue) {
                                 result = status;
                                 val1 = effectiveValue;
                             });
-        ASSERT_TRUE(result == EvsResult::OK ||
-                    result == EvsResult::INVALID_ARG);
+        ASSERT_EQ(EvsResult::OK, result);
 
         // Verify a change notification
-        if (result == EvsResult::OK) {
-            bool timeout =
-                frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
-            ASSERT_FALSE(timeout) << "Expected event does not arrive";
-            ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
-                      InfoEventType::PARAMETER_CHANGED);
-            ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
-                      CameraParam::BRIGHTNESS);
-            ASSERT_EQ(val1,
-                      static_cast<int32_t>(aNotification.payload[1]));
-        }
+        timeout =
+            frameHandler1->waitForEvent(EvsEventType::PARAMETER_CHANGED, aNotification);
+        ASSERT_FALSE(timeout) << "Expected event does not arrive";
+        ASSERT_EQ(static_cast<EvsEventType>(aNotification.aType),
+                  EvsEventType::PARAMETER_CHANGED);
+        ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+                  cam0Cmds[0]);
+        ASSERT_EQ(val1,
+                  static_cast<int32_t>(aNotification.payload[1]));
 
         // Turn off the display (yes, before the stream stops -- it should be handled)
         pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
@@ -1061,6 +1264,248 @@
 }
 
 
+/*
+ * CameraUseStreamConfigToDisplay:
+ * End to end test of data flowing from the camera to the display.  Similar to
+ * CameraToDisplayRoundTrip test case but this case retrieves available stream
+ * configurations from EVS and uses one of them to start a video stream.
+ */
+TEST_F(EvsHidlTest, CameraUseStreamConfigToDisplay) {
+    ALOGI("Starting CameraUseStreamConfigToDisplay test");
+
+    // Get the camera list
+    loadCameraList();
+
+    // Request exclusive access to the EVS display
+    sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+    ASSERT_NE(pDisplay, nullptr);
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // choose a configuration that has a frame rate faster than minReqFps.
+        Stream targetCfg = {};
+        const int32_t minReqFps = 15;
+        int32_t maxArea = 0;
+        camera_metadata_entry_t streamCfgs;
+        bool foundCfg = false;
+        if (!find_camera_metadata_entry(
+                 reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+                 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                 &streamCfgs)) {
+            // Stream configurations are found in metadata
+            RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+            for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+                    if (ptr->width * ptr->height > maxArea &&
+                        ptr->framerate >= minReqFps) {
+                        targetCfg.width = ptr->width;
+                        targetCfg.height = ptr->height;
+
+                        maxArea = ptr->width * ptr->height;
+                        foundCfg = true;
+                    }
+                }
+                ++ptr;
+            }
+        }
+        targetCfg.format =
+            static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+        if (!foundCfg) {
+            // Current EVS camera does not provide stream configurations in the
+            // metadata.
+            continue;
+        }
+
+        sp<IEvsCamera_1_1> pCam =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam, nullptr);
+
+        // Set up a frame receiver object which will fire up its own thread.
+        sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
+                                                         pDisplay,
+                                                         FrameHandler::eAutoReturn);
+
+
+        // Activate the display
+        pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+        // Start the camera's video stream
+        bool startResult = frameHandler->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Wait a while to let the data flow
+        static const int kSecondsToWait = 5;
+        const int streamTimeMs = kSecondsToWait * kSecondsToMilliseconds -
+                                 kMaxStreamStartMilliseconds;
+        const unsigned minimumFramesExpected = streamTimeMs * kMinimumFramesPerSecond /
+                                               kSecondsToMilliseconds;
+        sleep(kSecondsToWait);
+        unsigned framesReceived = 0;
+        unsigned framesDisplayed = 0;
+        frameHandler->getFramesCounters(&framesReceived, &framesDisplayed);
+        EXPECT_EQ(framesReceived, framesDisplayed);
+        EXPECT_GE(framesDisplayed, minimumFramesExpected);
+
+        // Turn off the display (yes, before the stream stops -- it should be handled)
+        pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+        // Shut down the streamer
+        frameHandler->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam);
+    }
+
+    // Explicitly release the display
+    pEnumerator->closeDisplay(pDisplay);
+}
+
+
+/*
+ * MultiCameraStreamUseConfig:
+ * Verify that each client can start and stop video streams on the same
+ * underlying camera with same configuration.
+ */
+TEST_F(EvsHidlTest, MultiCameraStreamUseConfig) {
+    ALOGI("Starting MultiCameraStream test");
+
+    if (mIsHwModule) {
+        // This test is not for HW module implementation.
+        return;
+    }
+
+    // Get the camera list
+    loadCameraList();
+
+    // Test each reported camera
+    for (auto&& cam: cameraInfo) {
+        // choose a configuration that has a frame rate faster than minReqFps.
+        Stream targetCfg = {};
+        const int32_t minReqFps = 15;
+        int32_t maxArea = 0;
+        camera_metadata_entry_t streamCfgs;
+        bool foundCfg = false;
+        if (!find_camera_metadata_entry(
+                 reinterpret_cast<camera_metadata_t *>(cam.metadata.data()),
+                 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                 &streamCfgs)) {
+            // Stream configurations are found in metadata
+            RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+            for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+
+                    if (ptr->width * ptr->height > maxArea &&
+                        ptr->framerate >= minReqFps) {
+                        targetCfg.width = ptr->width;
+                        targetCfg.height = ptr->height;
+
+                        maxArea = ptr->width * ptr->height;
+                        foundCfg = true;
+                    }
+                }
+                ++ptr;
+            }
+        }
+        targetCfg.format =
+            static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
+
+        if (!foundCfg) {
+            ALOGI("Device %s does not provide a list of supported stream configurations, skipped",
+                  cam.v1.cameraId.c_str());
+
+            continue;
+        }
+
+        // Create the first camera client with a selected stream configuration.
+        sp<IEvsCamera_1_1> pCam0 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam0, nullptr);
+
+        // Try to create the second camera client with different stream
+        // configuration.
+        int32_t id = targetCfg.id;
+        targetCfg.id += 1;  // EVS manager sees only the stream id.
+        sp<IEvsCamera_1_1> pCam1 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+            .withDefault(nullptr);
+        ASSERT_EQ(pCam1, nullptr);
+
+        // Try again with same stream configuration.
+        targetCfg.id = id;
+        pCam1 =
+            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
+            .withDefault(nullptr);
+        ASSERT_NE(pCam1, nullptr);
+
+        // Set up per-client frame receiver objects which will fire up its own thread
+        sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+                                                          nullptr,
+                                                          FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandler0, nullptr);
+
+        sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+                                                          nullptr,
+                                                          FrameHandler::eAutoReturn);
+        ASSERT_NE(frameHandler1, nullptr);
+
+        // Start the camera's video stream via client 0
+        bool startResult = false;
+        startResult = frameHandler0->startStream() &&
+                      frameHandler1->startStream();
+        ASSERT_TRUE(startResult);
+
+        // Ensure the stream starts
+        frameHandler0->waitForFrameCount(1);
+        frameHandler1->waitForFrameCount(1);
+
+        nsecs_t firstFrame = systemTime(SYSTEM_TIME_MONOTONIC);
+
+        // Wait a bit, then ensure both clients get at least the required minimum number of frames
+        sleep(5);
+        nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+        unsigned framesReceived0 = 0, framesReceived1 = 0;
+        frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+        framesReceived0 = framesReceived0 - 1;    // Back out the first frame we already waited for
+        framesReceived1 = framesReceived1 - 1;    // Back out the first frame we already waited for
+        nsecs_t runTime = end - firstFrame;
+        float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
+        float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
+        ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+        EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
+        EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
+
+        // Shutdown one client
+        frameHandler0->shutdown();
+
+        // Read frame counters again
+        frameHandler0->getFramesCounters(&framesReceived0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceived1, nullptr);
+
+        // Wait a bit again
+        sleep(5);
+        unsigned framesReceivedAfterStop0 = 0, framesReceivedAfterStop1 = 0;
+        frameHandler0->getFramesCounters(&framesReceivedAfterStop0, nullptr);
+        frameHandler1->getFramesCounters(&framesReceivedAfterStop1, nullptr);
+        EXPECT_EQ(framesReceived0, framesReceivedAfterStop0);
+        EXPECT_LT(framesReceived1, framesReceivedAfterStop1);
+
+        // Shutdown another
+        frameHandler1->shutdown();
+
+        // Explicitly release the camera
+        pEnumerator->closeCamera(pCam0);
+        pEnumerator->closeCamera(pCam1);
+    }
+}
+
+
 int main(int argc, char** argv) {
     ::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
diff --git a/boot/1.1/Android.bp b/boot/1.1/Android.bp
new file mode 100644
index 0000000..6a8d57a
--- /dev/null
+++ b/boot/1.1/Android.bp
@@ -0,0 +1,18 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.boot@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IBootControl.hal",
+    ],
+    interfaces: [
+        "android.hardware.boot@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/boot/1.1/IBootControl.hal b/boot/1.1/IBootControl.hal
new file mode 100644
index 0000000..939dfb3
--- /dev/null
+++ b/boot/1.1/IBootControl.hal
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.boot@1.1;
+
+import @1.0::IBootControl;
+
+interface IBootControl extends @1.0::IBootControl {
+    /**
+     * Sets whether a snapshot-merge of any dynamic partition is in progress.
+     *
+     * After the merge status is set to a given value, subsequent calls to
+     * getSnapshotMergeStatus must return the set value.
+     *
+     * The merge status must be persistent across reboots. That is, getSnapshotMergeStatus
+     * must return the same value after a reboot if the merge status is not altered in any way
+     * (e.g. set by setSnapshotMergeStatus or set to CANCELLED by bootloader).
+     *
+     * Read/write access to the merge status must be atomic. When the HAL is processing a
+     * setSnapshotMergeStatus call, all subsequent calls to getSnapshotMergeStatus must block until
+     * setSnapshotMergeStatus has returned.
+     *
+     * A MERGING state indicates that dynamic partitions are partially comprised by blocks in the
+     * userdata partition.
+     *
+     * When the merge status is set to MERGING, the following operations must be prohibited from the
+     * bootloader:
+     *  - Flashing or erasing "userdata" or "metadata".
+     *
+     * The following operations may be prohibited when the status is set to MERGING. If not
+     * prohibited, it is recommended that the user receive a warning.
+     *  - Changing the active slot (e.g. via "fastboot set_active")
+     *
+     * @param status Merge status.
+     *
+     * @return success True on success, false otherwise.
+     */
+    setSnapshotMergeStatus(MergeStatus status) generates (bool success);
+
+    /**
+     * Returns whether a snapshot-merge of any dynamic partition is in progress.
+     *
+     * This function must return the merge status set by the last setSnapshotMergeStatus call and
+     * recorded by the bootloader with one exception. If the partitions are being flashed from the
+     * bootloader such that the pending merge must be canceled (for example, if the super partition
+     * is being flashed), this function must return CANCELLED.
+     *
+     * @return success True if the merge status is read successfully, false otherwise.
+     * @return status Merge status.
+     */
+    getSnapshotMergeStatus() generates (MergeStatus status);
+};
+
diff --git a/boot/1.1/default/Android.bp b/boot/1.1/default/Android.bp
new file mode 100644
index 0000000..dca5c26
--- /dev/null
+++ b/boot/1.1/default/Android.bp
@@ -0,0 +1,43 @@
+cc_library_shared {
+    name: "android.hardware.boot@1.1-impl",
+    defaults: [
+        "hidl_defaults",
+        "libboot_control_defaults",
+    ],
+    relative_install_path: "hw",
+    vendor: true,
+    recovery_available: true,
+    srcs: ["BootControl.cpp"],
+
+    shared_libs: [
+        "liblog",
+        "libhidlbase",
+        "libhardware",
+        "libutils",
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
+    ],
+    static_libs: [
+        "libboot_control",
+        "libfstab",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.boot@1.1-service",
+    defaults: ["hidl_defaults"],
+    relative_install_path: "hw",
+    vendor: true,
+    init_rc: ["android.hardware.boot@1.1-service.rc"],
+    srcs: ["service.cpp"],
+
+    shared_libs: [
+        "liblog",
+        "libhardware",
+        "libhidlbase",
+        "libutils",
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
+    ],
+
+}
diff --git a/boot/1.1/default/BootControl.cpp b/boot/1.1/default/BootControl.cpp
new file mode 100644
index 0000000..c9c62a4
--- /dev/null
+++ b/boot/1.1/default/BootControl.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.boot@1.1-impl"
+
+#include <memory>
+
+#include <log/log.h>
+
+#include "BootControl.h"
+
+namespace android {
+namespace hardware {
+namespace boot {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::boot::V1_0::CommandResult;
+
+bool BootControl::Init() {
+    return impl_.Init();
+}
+
+// Methods from ::android::hardware::boot::V1_0::IBootControl follow.
+Return<uint32_t> BootControl::getNumberSlots() {
+    return impl_.GetNumberSlots();
+}
+
+Return<uint32_t> BootControl::getCurrentSlot() {
+    return impl_.GetCurrentSlot();
+}
+
+Return<void> BootControl::markBootSuccessful(markBootSuccessful_cb _hidl_cb) {
+    struct CommandResult cr;
+    if (impl_.MarkBootSuccessful()) {
+        cr.success = true;
+        cr.errMsg = "Success";
+    } else {
+        cr.success = false;
+        cr.errMsg = "Operation failed";
+    }
+    _hidl_cb(cr);
+    return Void();
+}
+
+Return<void> BootControl::setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) {
+    struct CommandResult cr;
+    if (impl_.SetActiveBootSlot(slot)) {
+        cr.success = true;
+        cr.errMsg = "Success";
+    } else {
+        cr.success = false;
+        cr.errMsg = "Operation failed";
+    }
+    _hidl_cb(cr);
+    return Void();
+}
+
+Return<void> BootControl::setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) {
+    struct CommandResult cr;
+    if (impl_.SetSlotAsUnbootable(slot)) {
+        cr.success = true;
+        cr.errMsg = "Success";
+    } else {
+        cr.success = false;
+        cr.errMsg = "Operation failed";
+    }
+    _hidl_cb(cr);
+    return Void();
+}
+
+Return<BoolResult> BootControl::isSlotBootable(uint32_t slot) {
+    if (!impl_.IsValidSlot(slot)) {
+        return BoolResult::INVALID_SLOT;
+    }
+    return impl_.IsSlotBootable(slot) ? BoolResult::TRUE : BoolResult::FALSE;
+}
+
+Return<BoolResult> BootControl::isSlotMarkedSuccessful(uint32_t slot) {
+    if (!impl_.IsValidSlot(slot)) {
+        return BoolResult::INVALID_SLOT;
+    }
+    return impl_.IsSlotMarkedSuccessful(slot) ? BoolResult::TRUE : BoolResult::FALSE;
+}
+
+Return<void> BootControl::getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) {
+    hidl_string ans;
+    const char* suffix = impl_.GetSuffix(slot);
+    if (suffix) {
+        ans = suffix;
+    }
+    _hidl_cb(ans);
+    return Void();
+}
+
+Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus status) {
+    return impl_.SetSnapshotMergeStatus(status);
+}
+
+Return<MergeStatus> BootControl::getSnapshotMergeStatus() {
+    return impl_.GetSnapshotMergeStatus();
+}
+
+IBootControl* HIDL_FETCH_IBootControl(const char* /* hal */) {
+    auto module = std::make_unique<BootControl>();
+    if (!module->Init()) {
+        ALOGE("Could not initialize BootControl module");
+        return nullptr;
+    }
+    return module.release();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace boot
+}  // namespace hardware
+}  // namespace android
diff --git a/boot/1.1/default/BootControl.h b/boot/1.1/default/BootControl.h
new file mode 100644
index 0000000..75511b6
--- /dev/null
+++ b/boot/1.1/default/BootControl.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/boot/1.1/IBootControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <libboot_control/libboot_control.h>
+
+namespace android {
+namespace hardware {
+namespace boot {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::boot::V1_0::BoolResult;
+using ::android::hardware::boot::V1_1::IBootControl;
+using ::android::hardware::boot::V1_1::MergeStatus;
+
+class BootControl : public IBootControl {
+  public:
+    bool Init();
+
+    // Methods from ::android::hardware::boot::V1_0::IBootControl follow.
+    Return<uint32_t> getNumberSlots() override;
+    Return<uint32_t> getCurrentSlot() override;
+    Return<void> markBootSuccessful(markBootSuccessful_cb _hidl_cb) override;
+    Return<void> setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) override;
+    Return<void> setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) override;
+    Return<BoolResult> isSlotBootable(uint32_t slot) override;
+    Return<BoolResult> isSlotMarkedSuccessful(uint32_t slot) override;
+    Return<void> getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) override;
+
+    // Methods from ::android::hardware::boot::V1_1::IBootControl follow.
+    Return<bool> setSnapshotMergeStatus(MergeStatus status) override;
+    Return<MergeStatus> getSnapshotMergeStatus() override;
+
+  private:
+    android::bootable::BootControl impl_;
+};
+
+extern "C" IBootControl* HIDL_FETCH_IBootControl(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace boot
+}  // namespace hardware
+}  // namespace android
diff --git a/boot/1.1/default/android.hardware.boot@1.1-service.rc b/boot/1.1/default/android.hardware.boot@1.1-service.rc
new file mode 100644
index 0000000..83fa9d0
--- /dev/null
+++ b/boot/1.1/default/android.hardware.boot@1.1-service.rc
@@ -0,0 +1,6 @@
+service vendor.boot-hal-1-1 /vendor/bin/hw/android.hardware.boot@1.1-service
+    interface android.hardware.boot@1.0::IBootControl default
+    interface android.hardware.boot@1.1::IBootControl default
+    class early_hal
+    user root
+    group root
diff --git a/boot/1.1/default/service.cpp b/boot/1.1/default/service.cpp
new file mode 100644
index 0000000..b24b464
--- /dev/null
+++ b/boot/1.1/default/service.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.boot@1.1-service"
+
+#include <android/hardware/boot/1.1/IBootControl.h>
+#include <hidl/LegacySupport.h>
+
+using android::hardware::defaultPassthroughServiceImplementation;
+using ::android::hardware::boot::V1_1::IBootControl;
+
+int main(int /* argc */, char* /* argv */[]) {
+    return defaultPassthroughServiceImplementation<IBootControl>();
+}
diff --git a/boot/1.1/types.hal b/boot/1.1/types.hal
new file mode 100644
index 0000000..6346078
--- /dev/null
+++ b/boot/1.1/types.hal
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.boot@1.1;
+
+enum MergeStatus : int32_t {
+    /**
+     * No snapshot or merge is in progress.
+     */
+    NONE = 0,
+
+    /**
+     * The merge status could not be determined.
+     */
+    UNKNOWN,
+
+    /**
+     * Partitions are being snapshotted, but no merge has been started.
+     */
+    SNAPSHOTTED,
+
+    /**
+     * At least one partition has merge is in progress.
+     */
+    MERGING,
+
+    /**
+     * A merge was in progress, but it was canceled by the bootloader.
+     */
+    CANCELLED,
+};
diff --git a/boot/1.1/vts/functional/Android.bp b/boot/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..49ea09a
--- /dev/null
+++ b/boot/1.1/vts/functional/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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: "VtsHalBootV1_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBootV1_1TargetTest.cpp"],
+    static_libs: [
+        "android.hardware.boot@1.0",
+        "android.hardware.boot@1.1",
+        "libgmock",
+    ],
+    test_suites: ["device-tests"],
+}
+
diff --git a/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
new file mode 100644
index 0000000..fba9a5e
--- /dev/null
+++ b/boot/1.1/vts/functional/VtsHalBootV1_1TargetTest.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "boot_hidl_hal_test"
+
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android/hardware/boot/1.1/IBootControl.h>
+#include <android/hardware/boot/1.1/types.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <unistd.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::boot::V1_1::IBootControl;
+using ::android::hardware::boot::V1_1::MergeStatus;
+using ::testing::Contains;
+
+class BootHidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        boot = IBootControl::getService(GetParam());
+        ASSERT_NE(boot, nullptr);
+
+        LOG(INFO) << "Test is remote " << boot->isRemote();
+    }
+
+    sp<IBootControl> boot;
+};
+
+static std::vector<MergeStatus> ValidMergeStatusValues() {
+    std::vector<MergeStatus> values;
+    for (const auto value : hidl_enum_range<MergeStatus>()) {
+        if (value == MergeStatus::UNKNOWN) {
+            continue;
+        }
+        values.push_back(value);
+    }
+    return values;
+}
+
+/**
+ * Ensure merge status can be retrieved.
+ */
+TEST_P(BootHidlTest, GetSnapshotMergeStatus) {
+    auto values = ValidMergeStatusValues();
+    auto status = (MergeStatus)boot->getSnapshotMergeStatus();
+    EXPECT_THAT(values, Contains(status));
+}
+
+/**
+ * Ensure merge status can be set to arbitrary value.
+ */
+TEST_P(BootHidlTest, SetSnapshotMergeStatus) {
+    for (const auto value : ValidMergeStatusValues()) {
+        EXPECT_TRUE(boot->setSnapshotMergeStatus(value).withDefault(false));
+        auto status = boot->getSnapshotMergeStatus();
+        EXPECT_EQ(status, value);
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        , BootHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBootControl::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 409c5a2..a409650 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -89,7 +89,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.boot</name>
-        <version>1.0</version>
+        <version>1.1</version>
         <interface>
             <name>IBootControl</name>
             <instance>default</instance>
diff --git a/contexthub/1.0/default/OWNERS b/contexthub/1.0/default/OWNERS
index 5373073..90c2330 100644
--- a/contexthub/1.0/default/OWNERS
+++ b/contexthub/1.0/default/OWNERS
@@ -1,4 +1,3 @@
-aarossig@google.com
 arthuri@google.com
 bduddie@google.com
-bstack@google.com
+stange@google.com
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
index ee01441..045cc4e 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -1,8 +1,7 @@
 #Context Hub team
-aarossig@google.com
 arthuri@google.com
 bduddie@google.com
-bstack@google.com
+stange@google.com
 
 #VTS team
 yim@google.com
diff --git a/current.txt b/current.txt
index e164a3f..87498a1 100644
--- a/current.txt
+++ b/current.txt
@@ -585,8 +585,10 @@
 fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
 
 # HALs released in Android R
+07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
+74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
 34515afa2bb792d3c6d8495a5f5d907d179c8507ca5e55c10050d02ae1d516ef android.hardware.neuralnetworks@1.3::IDevice
-e2d20d4eb24f40b44a3766d05f77052581cb3f4df35fb48c0cc5d9cdcf5c872e android.hardware.neuralnetworks@1.3::types
+b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types
 04395b26be33db17747c3d3b0e8066d323f891ff4f9f3b3ddb490b2f3f844a18 android.hardware.wifi@1.4::IWifi
 270f0eb670dfd9bc5cd718e09711f2534fa8425f54d06c1a46523ca156b509e2 android.hardware.wifi.supplicant@1.3::ISupplicant
 dd4b7cfbb6e1c6ff011c33920762ad89dd02240c63a4d3a3d5037f154eae3e3b android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
diff --git a/drm/TEST_MAPPING b/drm/TEST_MAPPING
new file mode 100644
index 0000000..cff6819
--- /dev/null
+++ b/drm/TEST_MAPPING
@@ -0,0 +1,8 @@
+{
+  "imports": [
+    // gts and cts filters
+    {
+      "path": "frameworks/av/drm/libmediadrm"
+    }
+  ]
+}
diff --git a/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h b/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
index 5ad2a65..8134174 100644
--- a/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
+++ b/graphics/mapper/2.0/utils/hal/include/mapper-hal/2.0/Mapper.h
@@ -80,17 +80,21 @@
     }
 
     Return<Error> freeBuffer(void* buffer) override {
-        native_handle_t* bufferHandle = removeImportedBuffer(buffer);
+        native_handle_t* bufferHandle = getImportedBuffer(buffer);
         if (!bufferHandle) {
             return Error::BAD_BUFFER;
         }
 
-        return mHal->freeBuffer(bufferHandle);
+        Error error = mHal->freeBuffer(bufferHandle);
+        if (error == Error::NONE) {
+            removeImportedBuffer(buffer);
+        }
+        return error;
     }
 
     Return<void> lock(void* buffer, uint64_t cpuUsage, const V2_0::IMapper::Rect& accessRegion,
                       const hidl_handle& acquireFence, IMapper::lock_cb hidl_cb) override {
-        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        const native_handle_t* bufferHandle = getConstImportedBuffer(buffer);
         if (!bufferHandle) {
             hidl_cb(Error::BAD_BUFFER, nullptr);
             return Void();
@@ -112,7 +116,7 @@
     Return<void> lockYCbCr(void* buffer, uint64_t cpuUsage, const V2_0::IMapper::Rect& accessRegion,
                            const hidl_handle& acquireFence,
                            IMapper::lockYCbCr_cb hidl_cb) override {
-        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        const native_handle_t* bufferHandle = getConstImportedBuffer(buffer);
         if (!bufferHandle) {
             hidl_cb(Error::BAD_BUFFER, YCbCrLayout{});
             return Void();
@@ -132,7 +136,7 @@
     }
 
     Return<void> unlock(void* buffer, IMapper::unlock_cb hidl_cb) override {
-        const native_handle_t* bufferHandle = getImportedBuffer(buffer);
+        const native_handle_t* bufferHandle = getConstImportedBuffer(buffer);
         if (!bufferHandle) {
             hidl_cb(Error::BAD_BUFFER, nullptr);
             return Void();
@@ -160,7 +164,11 @@
         return static_cast<native_handle_t*>(buffer);
     }
 
-    virtual const native_handle_t* getImportedBuffer(void* buffer) const {
+    virtual native_handle_t* getImportedBuffer(void* buffer) const {
+        return static_cast<native_handle_t*>(buffer);
+    }
+
+    virtual const native_handle_t* getConstImportedBuffer(void* buffer) const {
         return static_cast<const native_handle_t*>(buffer);
     }
 
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
index e8b1b4b..85a91c3 100644
--- a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/GrallocLoader.h
@@ -68,7 +68,14 @@
         return mBufferHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr;
     }
 
-    const native_handle_t* get(void* buffer) {
+    native_handle_t* get(void* buffer) {
+        auto bufferHandle = static_cast<native_handle_t*>(buffer);
+
+        std::lock_guard<std::mutex> lock(mMutex);
+        return mBufferHandles.count(bufferHandle) == 1 ? bufferHandle : nullptr;
+    }
+
+    const native_handle_t* getConst(void* buffer) {
         auto bufferHandle = static_cast<const native_handle_t*>(buffer);
 
         std::lock_guard<std::mutex> lock(mMutex);
@@ -92,9 +99,13 @@
         return GrallocImportedBufferPool::getInstance().remove(buffer);
     }
 
-    const native_handle_t* getImportedBuffer(void* buffer) const override {
+    native_handle_t* getImportedBuffer(void* buffer) const override {
         return GrallocImportedBufferPool::getInstance().get(buffer);
     }
+
+    const native_handle_t* getConstImportedBuffer(void* buffer) const override {
+        return GrallocImportedBufferPool::getInstance().getConst(buffer);
+    }
 };
 
 class GrallocLoader {
diff --git a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
index 97dab68..cb29c64 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/keymaster_tags.h
@@ -280,39 +280,50 @@
  */
 template <typename ValueT>
 class NullOr {
-    template <typename T>
-    struct reference_initializer {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wnull-dereference"
-        static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); }
-#pragma GCC diagnostic pop
-    };
-    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>>>;
+    using internal_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value,
+                                          std::remove_reference_t<ValueT>*, ValueT>;
 
-   public:
-    NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {}
-    NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {}
+    struct pointer_initializer {
+        static std::nullptr_t init() { return nullptr; }
+    };
+    struct value_initializer {
+        static ValueT init() { return ValueT(); }
+    };
+    struct value_pointer_deref_t {
+        static ValueT& deref(ValueT& v) { return v; }
+    };
+    struct reference_deref_t {
+        static auto& deref(internal_t v) { return *v; }
+    };
+    using initializer_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value ||
+                                                     std::is_pointer<ValueT>::value,
+                                             pointer_initializer, value_initializer>;
+    using deref_t = std::conditional_t<std::is_lvalue_reference<ValueT>::value, reference_deref_t,
+                                       value_pointer_deref_t>;
+
+  public:
+    NullOr() : value_(initializer_t::init()), null_(true) {}
+    template <typename T>
+    NullOr(T&& value, typename std::enable_if<
+                              !std::is_lvalue_reference<ValueT>::value &&
+                                      std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value,
+                              int>::type = 0)
+        : value_(std::forward<ValueT>(value)), null_(false) {}
+    template <typename T>
+    NullOr(T& value, typename std::enable_if<
+                             std::is_lvalue_reference<ValueT>::value &&
+                                     std::is_same<std::decay_t<ValueT>, std::decay_t<T>>::value,
+                             int>::type = 0)
+        : value_(&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 ValueT& value() const& { return deref_t::deref(value_); }
+    ValueT& value() & { return deref_t::deref(value_); }
+    ValueT&& value() && { return std::move(deref_t::deref(value_)); }
 
-   private:
-    ValueT value_;
+  private:
+    internal_t value_;
     bool null_;
 };
 
diff --git a/light/utils/main.cpp b/light/utils/main.cpp
index d07e799..b834132 100644
--- a/light/utils/main.cpp
+++ b/light/utils/main.cpp
@@ -25,7 +25,7 @@
     std::cerr << msg << std::endl;
 }
 
-int main() {
+int main(int argc, char* argv[]) {
     using ::android::hardware::hidl_vec;
     using ::android::hardware::light::V2_0::Brightness;
     using ::android::hardware::light::V2_0::Flash;
@@ -41,10 +41,29 @@
         return -1;
     }
 
-    const static LightState off = {
-        .color = 0u, .flashMode = Flash::NONE, .brightnessMode = Brightness::USER,
+    static LightState off = {
+            .color = 0u,
+            .flashMode = Flash::NONE,
+            .brightnessMode = Brightness::USER,
     };
 
+    if (argc > 2) {
+        error("Usage: blank_screen [color]");
+        return -1;
+    }
+
+    if (argc > 1) {
+        char* col_ptr;
+        unsigned int col_new;
+
+        col_new = strtoul(argv[1], &col_ptr, 0);
+        if (*col_ptr != '\0') {
+            error("Failed to convert " + std::string(argv[1]) + " to number");
+            return -1;
+        }
+        off.color = col_new;
+    }
+
     service->getSupportedTypes([&](const hidl_vec<Type>& types) {
         for (Type type : types) {
             Status ret = service->setLight(type, off);
diff --git a/neuralnetworks/1.2/types.t b/neuralnetworks/1.2/types.t
index cab330d..d197f6b 100644
--- a/neuralnetworks/1.2/types.t
+++ b/neuralnetworks/1.2/types.t
@@ -41,27 +41,7 @@
 
 enum OperandType : @1.0::OperandType {
 %insert Operand_1.2
-
-    /*
-     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
-     * alternative to OEM operation and data types.
-     *
-     * OEM specific scalar value.
-     * OEM                 = 10000,
-     */
-    /*
-     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
-     * alternative to OEM operation and data types.
-     *
-     * A tensor of OEM specific values.
-     * TENSOR_OEM_BYTE     = 10001,
-     */
-    /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF
-     * OperandTypeRange::FUNDAMENTAL_MAX.
-     */
-    /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF
-     * OperandTypeRange::OEM_MAX.
-     */
+%insert OEMDeprecationAndOperandTypeRangeMaxComment
 };
 
 /**
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index db5dd51..86ab287 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -25,13 +25,6 @@
 
 import android.hidl.safe_union@1.0::Monostate;
 
-/**
- * NOTE: Since NNAPI 1.2, OEM operation and data type are deprecated. Extensions
- * are the preferred alternative.
- *
- * NOTE: Adding a new fundamental type requires updating the value of
- * OperandTypeRange::FUNDAMENTAL_MAX.
- */
 enum OperandType : @1.2::OperandType {
     /**
      * A tensor of 8 bit signed integers that represent real numbers.
@@ -43,10 +36,29 @@
      *
      * The formula is:
      * real_value = (integer_value - zeroPoint) * scale.
-     *
-     * Available since API level 30.
      */
     TENSOR_QUANT8_ASYMM_SIGNED = 14,
+
+    /*
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
+     *
+     * OEM specific scalar value.
+     * OEM                 = 10000,
+     */
+    /*
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
+     *
+     * A tensor of OEM specific values.
+     * TENSOR_OEM_BYTE     = 10001,
+     */
+    /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF
+     * OperandTypeRange::FUNDAMENTAL_MAX.
+     */
+    /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF
+     * OperandTypeRange::OEM_MAX.
+     */
 };
 
 /**
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
new file mode 100644
index 0000000..d41cfd2
--- /dev/null
+++ b/neuralnetworks/1.3/types.t
@@ -0,0 +1,344 @@
+%% template file for generating types.hal.
+%% see frameworks/ml/nn/tools/api/README.md.
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.neuralnetworks@1.3;
+
+import @1.0::DataLocation;
+import @1.0::OperandLifeTime;
+import @1.0::PerformanceInfo;
+import @1.2::OperandType;
+import @1.2::OperationType;
+import @1.2::SymmPerChannelQuantParams;
+
+import android.hidl.safe_union@1.0::Monostate;
+
+enum OperandType : @1.2::OperandType {
+%insert Operand_1.3
+%insert OEMDeprecationAndOperandTypeRangeMaxComment
+};
+
+/**
+ * The range of operand values in the OperandType enum.
+ */
+enum OperandTypeRange : uint32_t {
+    BASE_MIN        = 0,
+    FUNDAMENTAL_MIN = 0,
+%insert Operand_1.3_MAX
+    OEM_MIN         = 10000,
+    OEM_MAX         = 10001,
+    BASE_MAX        = 0xFFFF,
+};
+
+
+/**
+ * The capabilities of a driver.
+ *
+ * Performance of an operation comes from the type of its first operand.
+ * This represents performance for non extension operand types.
+ */
+struct Capabilities {
+    /**
+     * Driver performance when operating on float32 data but performing
+     * calculations with range and/or precision as low as that of the IEEE
+     * 754 16-bit floating-point format.
+     */
+    PerformanceInfo relaxedFloat32toFloat16PerformanceScalar;
+    PerformanceInfo relaxedFloat32toFloat16PerformanceTensor;
+
+    /**
+     * Driver performance when operating on a particular data type.
+     * In the case of float32 data, this is used when the calculations
+     * are not relaxed.
+     */
+    struct OperandPerformance {
+        OperandType type;
+        PerformanceInfo info;
+    };
+
+    /**
+     * Performance by operand type. Must be sorted by OperandType.
+     * If a particular OperandType is not present in operandPerformance,
+     * its performance is treated as
+     * { .execTime = FLT_MAX, .powerUsage = FLT_MAX }.
+     */
+    vec<OperandPerformance> operandPerformance;
+};
+
+/**
+ * Describes one operand of the model's graph.
+ */
+struct Operand {
+    /**
+     * The data type.
+     *
+     * Besides the values listed in {@link OperandType}, any value above
+     * {@link OperandTypeRange::BASE_MAX} is possible and should be interpreted
+     * as an extension type according to {@link Model::extensionNameToPrefix}.
+     */
+    OperandType type;
+
+    /**
+     * Dimensions of the operand.
+     *
+     * For a scalar operand, dimensions.size() must be 0.
+     *
+     * A tensor operand with all dimensions specified has "fully
+     * specified" dimensions. Whenever possible (i.e., whenever the
+     * dimensions are known at model construction time), a tensor
+     * operand should have (but is not required to have) fully
+     * specified dimensions, in order to enable the best possible
+     * performance.
+     *
+     * If a tensor operand's dimensions are not fully specified, the
+     * dimensions of the operand are deduced from the operand
+     * dimensions and values of the operation for which that operand
+     * is an output.
+     *
+     * In the following situations, a tensor operand's dimensions must
+     * be fully specified:
+     *
+     *     . The operand has lifetime CONSTANT_COPY or
+     *       CONSTANT_REFERENCE.
+     *
+     *     . The operand has lifetime MODEL_INPUT. Fully
+     *       specified dimensions must either be present in the
+     *       Operand or they must be provided in the corresponding
+     *       RequestArgument.
+     *       EXCEPTION: If the input is optional and omitted
+     *       (by setting the hasNoValue field of the corresponding
+     *       RequestArgument to true) then it need not have fully
+     *       specified dimensions.
+     *
+     * A tensor operand with some number of unspecified dimensions is
+     * represented by setting each unspecified dimension to 0.
+     *
+     * A tensor operand with unspecified rank is represented by providing
+     * an empty dimensions vector.
+     */
+    vec<uint32_t> dimensions;
+
+    /**
+     * The number of times this operand appears as an operation input.
+     *
+     * (For example, if this operand appears once in one operation's
+     * input list, and three times in another operation's input list,
+     * then numberOfConsumers = 4.)
+     */
+    uint32_t numberOfConsumers;
+
+    /**
+     * Quantized scale of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or
+     * TENSOR_INT32.
+     */
+    float scale;
+
+    /**
+     * Quantized zero-point offset of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM.
+     */
+    int32_t zeroPoint;
+
+    /**
+     * How the operand is used.
+     */
+    OperandLifeTime lifetime;
+
+    /**
+     * Where to find the data for this operand.
+     * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
+     * NO_VALUE:
+     * - All the fields must be 0.
+     * If the lifetime is CONSTANT_COPY:
+     * - location.poolIndex is 0.
+     * - location.offset is the offset in bytes into Model.operandValues.
+     * - location.length is set.
+     * If the lifetime is CONSTANT_REFERENCE:
+     * - location.poolIndex is set.
+     * - location.offset is the offset in bytes into the specified pool.
+     * - location.length is set.
+     */
+    DataLocation location;
+
+    /**
+     * Additional parameters specific to a particular operand type.
+     */
+    safe_union ExtraParams {
+       /**
+        * No additional parameters.
+        */
+       Monostate none;
+
+       /**
+        * Symmetric per-channel quantization parameters.
+        *
+        * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL.
+        */
+       SymmPerChannelQuantParams channelQuant;
+
+       /**
+        * Extension operand parameters.
+        *
+        * The framework treats this as an opaque data blob.
+        * The format is up to individual extensions.
+        */
+       vec<uint8_t> extension;
+    } extraParams;
+};
+
+/**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+    /**
+     * The operation type.
+     */
+    OperationType type;
+
+    /**
+     * Describes the table that contains the indexes of the inputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> inputs;
+
+    /**
+     * Describes the table that contains the indexes of the outputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> outputs;
+};
+
+/**
+ * A Neural Network Model.
+ *
+ * This includes not only the execution graph, but also constant data such as
+ * weights or scalars added at construction time. The only information that
+ * may not be known is the shape of the input tensors.
+ */
+struct Model {
+    /**
+     * All operands included in the model.
+     */
+    vec<Operand> operands;
+
+    /**
+     * All operations included in the model.
+     *
+     * The operations are sorted into execution order. Every operand
+     * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
+     * written before it is read.
+     */
+    vec<Operation> operations;
+
+    /**
+     * Input indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> inputIndexes;
+
+    /**
+     * Output indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> outputIndexes;
+
+    /**
+     * A byte buffer containing operand data that were copied into the model.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_COPY.
+     */
+    vec<uint8_t> operandValues;
+
+    /**
+     * A collection of shared memory pools containing operand values.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_REFERENCE.
+     */
+    vec<memory> pools;
+
+    /**
+     * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or
+     * precision as low as that of the IEEE 754 16-bit floating-point format.
+     * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the
+     * range and precision of the IEEE 754 32-bit floating-point format.
+     */
+    bool relaxComputationFloat32toFloat16;
+
+    /**
+     * The mapping between extension names and prefixes of operand and
+     * operation type values.
+     *
+     * An operand or operation whose numeric type value is above
+     * {@link OperandTypeRange::BASE_MAX} or
+     * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
+     * as an extension operand. The low
+     * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
+     * correspond to the type ID within the extension and the high
+     * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+     * the "prefix", which maps uniquely to the extension name.
+     *
+     * For example, if a model contains an operation whose value is
+     * 0xAAAABBBB and extensionNameToPrefix contains an entry with
+     * prefix=0xAAAA and name="vendor.test.test_extension", then
+     * the operation should be interpreted as the operation 0xBBBB
+     * of the extension named vendor.test.test_extension.
+     *
+     * This is a one-to-one correspondence. That is, there must be at most one
+     * prefix corresponding to each extension name and at most one extension
+     * name corresponding to each prefix.
+     */
+    vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+
+    /**
+     * A correspondence between an extension name and a prefix of operand and
+     * operation type values.
+     */
+    struct ExtensionNameAndPrefix {
+        /**
+         * The extension name.
+         *
+         * See {@link Extension::name} for the format specification.
+         */
+        string name;
+
+        /**
+         * The unique extension identifier within the model.
+         *
+         * See {@link Model::extensionNameToPrefix}.
+         */
+        uint16_t prefix;
+    };
+
+    /**
+     * Numeric values of extension operand and operation types have the
+     * following structure:
+     * - 16 high bits represent the "prefix", which corresponds uniquely to the
+     *   extension name.
+     * - 16 low bits represent the type ID within the extension.
+     */
+    enum ExtensionTypeEncoding : uint8_t {
+        HIGH_BITS_PREFIX = 16,
+        LOW_BITS_TYPE = 16,
+    };
+};
diff --git a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
index 5184ef9..a98f22a 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.2/vts/functional/radio_hidl_hal_api.cpp
@@ -46,7 +46,10 @@
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
             .type = ScanType::ONE_SHOT,
             .interval = 60,
-            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850}};
+            .specifiers = {::GERAN_SPECIFIER_P900, ::GERAN_SPECIFIER_850},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
 
     Return<void> res = radio_v1_2->startNetworkScan_1_2(serial, request);
     ASSERT_OK(res);
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
index bf225bc..a4953d7 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
@@ -183,7 +183,12 @@
                                       .channels = {1, 2}};
 
     ::android::hardware::radio::V1_2::NetworkScanRequest request = {
-            .type = ScanType::ONE_SHOT, .interval = 60, .specifiers = {specifier}};
+            .type = ScanType::ONE_SHOT,
+            .interval = 60,
+            .specifiers = {specifier},
+            .maxSearchTime = 60,
+            .incrementalResults = false,
+            .incrementalResultsPeriodicity = 1};
 
     Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
     ASSERT_OK(res);
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 4faa562..b41730b 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
@@ -2,6 +2,6 @@
     interface android.hardware.sensors@1.0::ISensors default
     class hal
     user system
-    group system wakelock
+    group system wakelock uhid
     capabilities BLOCK_SUSPEND
     rlimit rtprio 10 10
diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal
index e03095b..7fd7e26 100644
--- a/tv/tuner/1.0/IDemux.hal
+++ b/tv/tuner/1.0/IDemux.hal
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.tv.tuner@1.0;
 
 import IDemuxCallback;
@@ -46,9 +62,9 @@
      *
      * It is used by the client to get the descriptor of the filter's Fast
      * Message Queue. The data in FMQ is filtered out from MPEG transport
-     * stream. The data is origanized to data blocks which may have
+     * stream. The data is organized to data blocks which may have
      * different length. The length's information of one or multiple data blocks
-     * is sent to client throught DemuxFilterEvent.
+     * is sent to client through DemuxFilterEvent.
      *
      * @param filterId the ID of the filter.
      * @return result Result status of the operation.
@@ -81,7 +97,7 @@
     /**
      * Start the filter.
      *
-     * It is used by the client to ask the filter to start filterring data.
+     * It is used by the client to ask the filter to start filtering data.
      *
      * @param filterId the ID of the filter.
      * @return result Result status of the operation.
@@ -202,7 +218,7 @@
      *
      * It is used by the client to get the descriptor of the output's Fast
      * Message Queue. The data in FMQ is muxed packets output from selected
-     * filters. The packet's format is specifed by DemuxDataFormat in
+     * filters. The packet's format is specified by DemuxDataFormat in
      * DemuxOutputSettings.
      *
      * @return result Result status of the operation.
@@ -236,7 +252,7 @@
      *         INVALID_STATE if failed for wrong state.
      *         UNKNOWN_ERROR if failed for other reasons.
      */
-    attachOutputTsFilter(DemuxFilterId filterId) generates (Result result);
+    attachOutputFilter(DemuxFilterId filterId) generates (Result result);
 
     /**
      * Detach one filter from the demux's output.
@@ -250,7 +266,7 @@
      *         INVALID_STATE if failed for wrong state.
      *         UNKNOWN_ERROR if failed for other reasons.
      */
-    detachOutputTsFilter(DemuxFilterId filterId) generates (Result result);
+    detachOutputFilter(DemuxFilterId filterId) generates (Result result);
 
     /**
      * Start to take data to the demux's output.
diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal
index 55e8420..7bce9ef 100644
--- a/tv/tuner/1.0/IDemuxCallback.hal
+++ b/tv/tuner/1.0/IDemuxCallback.hal
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.tv.tuner@1.0;
 
 interface IDemuxCallback {
diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal
index d078657..61ff1df 100644
--- a/tv/tuner/1.0/IDescrambler.hal
+++ b/tv/tuner/1.0/IDescrambler.hal
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.tv.tuner@1.0;
 /**
  * Descrambler is used to descramble input data.
diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
index 8788643..83e390d 100644
--- a/tv/tuner/1.0/IFrontend.hal
+++ b/tv/tuner/1.0/IFrontend.hal
@@ -145,10 +145,10 @@
      *         cable frontend.
      *         UNKNOWN_ERROR if failed for other reasons.
      */
-    setLnb(ILnb lnb) generates (Result result);
+    setLnb(LnbId lnbId) generates (Result result);
 
     /**
-     * Enble or Disable Low Noise Amplifier (LNA).
+     * Enable or Disable Low Noise Amplifier (LNA).
      *
      * @param bEnable true if activate LNA module; false if deactivate LNA
      *
@@ -158,22 +158,4 @@
      *         UNKNOWN_ERROR if failed for other reasons.
      */
     setLna(bool bEnable) generates (Result result);
-
-    /**
-     *  Sends DiSEqC (Digital Satellite Equipment Control) message.
-     *
-     * Client sends DiSeqc message to DiSEqc compatible device through the
-     * frontend. The response message from the device comes back to the client
-     * through frontend's callback onDiseqcMessage.
-     *
-     * @param diseqcMessage a byte array of data for DiSEqC message which is
-     *        specified by EUTELSAT Bus Functional Specification Version 4.2.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if the frontend can't send DiSEqc Message, such as
-     *         cable frontend.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    sendDiseqcMessage(vec<uint8_t> diseqcMessage) generates (Result result);
 };
diff --git a/tv/tuner/1.0/ILnb.hal b/tv/tuner/1.0/ILnb.hal
index 49fc3b4..6b7119e 100644
--- a/tv/tuner/1.0/ILnb.hal
+++ b/tv/tuner/1.0/ILnb.hal
@@ -55,6 +55,24 @@
     setSatellitePosition(FrontendLnbPosition position) generates (Result result);
 
     /**
+     *  Sends DiSEqC (Digital Satellite Equipment Control) message.
+     *
+     * Client sends DiSeqc message to DiSEqc to LNB. The response message from
+     * the device comes back to the client through frontend's callback
+     * onDiseqcMessage.
+     *
+     * @param diseqcMessage a byte array of data for DiSEqC message which is
+     *        specified by EUTELSAT Bus Functional Specification Version 4.2.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if the frontend can't send DiSEqc Message, such as
+     *         cable frontend.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    sendDiseqcMessage(vec<uint8_t> diseqcMessage) generates (Result result);
+
+    /**
      * Releases the LNB instance
      *
      * Associated resources are released.  close may be called more than once.
diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal
index f1a8617..1cf0e38 100644
--- a/tv/tuner/1.0/ITuner.hal
+++ b/tv/tuner/1.0/ITuner.hal
@@ -23,7 +23,7 @@
 
 /**
  * Top level interface to manage Frontend, Demux and Decrambler hardware
- * resouces which are needed for Android TV.
+ * resources which are needed for Android TV.
  */
 interface ITuner {
     /**
@@ -68,6 +68,16 @@
          generates (Result result, DemuxId demuxId, IDemux demux);
 
     /**
+     * Retrieve the Demux's Capabilities.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if the inquiry failed for other reasons.
+     * @return caps the Demux's Capabilities.
+     */
+    getDemuxCaps() generates (Result result, DemuxCapabilities caps);
+
+    /**
      * Create a new instance of Descrambler.
      *
      * It is used by the client to create a Descrambler instance.
@@ -81,14 +91,13 @@
          generates (Result result, IDescrambler descrambler);
 
     /**
-     * Create a new instance of Descrambler.
+     * Retrieve the frontend's information.
      *
-     * It is used by the client to create a Descrambler instance.
-     *
+     * @param frontendId the id of the frontend to be inquiried.
      * @return result Result status of the operation.
      *         SUCCESS if successful,
-     *         UNKNOWN_ERROR if creation failed for other reasons.
-     * @return descrambler the newly created descrambler interface.
+     *         UNKNOWN_ERROR if the inquiry failed for other reasons.
+     * @return info the frontend's information.
      */
     getFrontendInfo(FrontendId frontendId)
         generates (Result result, FrontendInfo info);
@@ -119,6 +128,5 @@
      */
     openLnbById(LnbId lnbId)
         generates (Result result, ILnb lnb);
-
 };
 
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index 889e42e..d65df59 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -67,8 +67,9 @@
         0x73, 0x63, 0x65, 0x6e, 0x65,
 };
 
-Demux::Demux(uint32_t demuxId) {
+Demux::Demux(uint32_t demuxId, sp<Tuner> tuner) {
     mDemuxId = demuxId;
+    mTunerService = tuner;
 }
 
 Demux::~Demux() {}
@@ -76,9 +77,20 @@
 Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
     ALOGV("%s", __FUNCTION__);
 
-    mSourceFrontendId = frontendId;
+    if (mTunerService == nullptr) {
+        return Result::NOT_INITIALIZED;
+    }
 
-    return Result::SUCCESS;
+    mFrontend = mTunerService->getFrontendById(frontendId);
+
+    if (mFrontend == nullptr) {
+        return Result::INVALID_STATE;
+    }
+
+    mFrontendSourceFile = mFrontend->getSourceFile();
+
+    mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
+    return startBroadcastInputLoop();
 }
 
 Return<void> Demux::addFilter(DemuxFilterType type, uint32_t bufferSize,
@@ -100,6 +112,8 @@
         mFilterEventFlags.resize(filterId + 1);
         mFilterThreadRunning.resize(filterId + 1);
         mFilterThreads.resize(filterId + 1);
+        mFilterPids.resize(filterId + 1);
+        mFilterOutputs.resize(filterId + 1);
     }
 
     mUsedFilterIds.insert(filterId);
@@ -142,10 +156,34 @@
     return Void();
 }
 
-Return<Result> Demux::configureFilter(uint32_t /* filterId */,
-                                      const DemuxFilterSettings& /* settings */) {
+Return<Result> Demux::configureFilter(uint32_t filterId, const DemuxFilterSettings& settings) {
     ALOGV("%s", __FUNCTION__);
 
+    switch (mFilterEvents[filterId].filterType) {
+        case DemuxFilterType::SECTION:
+            mFilterPids[filterId] = settings.section().tpid;
+            break;
+        case DemuxFilterType::PES:
+            mFilterPids[filterId] = settings.pesData().tpid;
+            break;
+        case DemuxFilterType::TS:
+            mFilterPids[filterId] = settings.ts().tpid;
+            break;
+        case DemuxFilterType::AUDIO:
+            mFilterPids[filterId] = settings.audio().tpid;
+            break;
+        case DemuxFilterType::VIDEO:
+            mFilterPids[filterId] = settings.video().tpid;
+            break;
+        case DemuxFilterType::RECORD:
+            mFilterPids[filterId] = settings.record().tpid;
+            break;
+        case DemuxFilterType::PCR:
+            mFilterPids[filterId] = settings.pcr().tpid;
+            break;
+        default:
+            return Result::UNKNOWN_ERROR;
+    }
     return Result::SUCCESS;
 }
 
@@ -158,36 +196,18 @@
         return Result::INVALID_ARGUMENT;
     }
 
-    switch (mFilterEvents[filterId].filterType) {
-        case DemuxFilterType::SECTION:
-            result = startFilterLoop(filterId);
-            break;
-        case DemuxFilterType::PES:
-            result = startPesFilterHandler(filterId);
-            break;
-        case DemuxFilterType::TS:
-            result = startTsFilterHandler();
-            return Result::SUCCESS;
-        case DemuxFilterType::AUDIO:
-        case DemuxFilterType::VIDEO:
-            result = startMediaFilterHandler(filterId);
-            break;
-        case DemuxFilterType::RECORD:
-            result = startRecordFilterHandler(filterId);
-            break;
-        case DemuxFilterType::PCR:
-            result = startPcrFilterHandler();
-            return Result::SUCCESS;
-        default:
-            return Result::UNKNOWN_ERROR;
-    }
+    result = startFilterLoop(filterId);
 
     return result;
 }
 
-Return<Result> Demux::stopFilter(uint32_t /* filterId */) {
+Return<Result> Demux::stopFilter(uint32_t filterId) {
     ALOGV("%s", __FUNCTION__);
 
+    mFilterThreadRunning[filterId] = false;
+
+    std::lock_guard<std::mutex> lock(mFilterThreadLock);
+
     return Result::SUCCESS;
 }
 
@@ -238,6 +258,8 @@
     mFilterMQs.clear();
     mFilterEvents.clear();
     mFilterEventFlags.clear();
+    mFilterOutputs.clear();
+    mFilterPids.clear();
     mLastUsedFilterId = -1;
 
     return Result::SUCCESS;
@@ -277,19 +299,21 @@
     return Void();
 }
 
-Return<Result> Demux::configureOutput(const DemuxOutputSettings& /* settings */) {
+Return<Result> Demux::configureOutput(const DemuxOutputSettings& settings) {
+    ALOGV("%s", __FUNCTION__);
+
+    mOutputConfigured = true;
+    mOutputSettings = settings;
+    return Result::SUCCESS;
+}
+
+Return<Result> Demux::attachOutputFilter(uint32_t /*filterId*/) {
     ALOGV("%s", __FUNCTION__);
 
     return Result::SUCCESS;
 }
 
-Return<Result> Demux::attachOutputTsFilter(uint32_t /*filterId*/) {
-    ALOGV("%s", __FUNCTION__);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::detachOutputTsFilter(uint32_t /* filterId */) {
+Return<Result> Demux::detachOutputFilter(uint32_t /* filterId */) {
     ALOGV("%s", __FUNCTION__);
 
     return Result::SUCCESS;
@@ -353,15 +377,26 @@
     return Void();
 }
 
-Return<Result> Demux::configureInput(const DemuxInputSettings& /* settings */) {
+Return<Result> Demux::configureInput(const DemuxInputSettings& settings) {
     ALOGV("%s", __FUNCTION__);
 
+    mInputConfigured = true;
+    mInputSettings = settings;
+
     return Result::SUCCESS;
 }
 
 Return<Result> Demux::startInput() {
     ALOGV("%s", __FUNCTION__);
 
+    if (!mInputCallback) {
+        return Result::NOT_INITIALIZED;
+    }
+
+    if (!mInputConfigured) {
+        return Result::INVALID_STATE;
+    }
+
     pthread_create(&mInputThread, NULL, __threadLoopInput, this);
     pthread_setname_np(mInputThread, "demux_input_waiting_loop");
 
@@ -373,6 +408,10 @@
 Return<Result> Demux::stopInput() {
     ALOGV("%s", __FUNCTION__);
 
+    mInputThreadRunning = false;
+
+    std::lock_guard<std::mutex> lock(mInputThreadLock);
+
     return Result::SUCCESS;
 }
 
@@ -403,36 +442,52 @@
     return Result::SUCCESS;
 }
 
-Result Demux::startSectionFilterHandler(uint32_t filterId, vector<uint8_t> data) {
-    if (!writeSectionsAndCreateEvent(filterId, data)) {
+Result Demux::startSectionFilterHandler(uint32_t filterId) {
+    if (mFilterOutputs[filterId].empty()) {
+        return Result::SUCCESS;
+    }
+    if (!writeSectionsAndCreateEvent(filterId, mFilterOutputs[filterId])) {
         ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId);
         return Result::UNKNOWN_ERROR;
     }
 
+    mFilterOutputs[filterId].clear();
+
     return Result::SUCCESS;
 }
 
 Result Demux::startPesFilterHandler(uint32_t filterId) {
-    // TODO generate multiple events in one event callback
+    std::lock_guard<std::mutex> lock(mFilterEventLock);
     DemuxFilterPesEvent pesEvent;
-    pesEvent = {
-            // temp dump meta data
-            .streamId = 0,
-            .dataLength = 530,
-    };
-    mFilterEvents[filterId].events.resize(1);
-    mFilterEvents[filterId].events[0].pes(pesEvent);
-    /*pthread_create(&mThreadId, NULL, __threadLoop, this);
-    pthread_setname_np(mThreadId, "demux_section_filter_waiting_loop");*/
-    if (!writeDataToFilterMQ(fakeDataInputBuffer, filterId)) {
-        return Result::INVALID_STATE;
+    if (mFilterOutputs[filterId].empty()) {
+        return Result::SUCCESS;
     }
 
-    if (mDemuxCallbacks[filterId] == nullptr) {
-        return Result::NOT_INITIALIZED;
+    for (int i = 0; i < mFilterOutputs[filterId].size(); i += 188) {
+        uint8_t pusi = mFilterOutputs[filterId][i + 1] & 0x40;
+        uint8_t adaptFieldControl = (mFilterOutputs[filterId][i + 3] & 0x30) >> 4;
+        ALOGD("[Demux] pusi %d, adaptFieldControl %d", pusi, adaptFieldControl);
+        if (pusi && (adaptFieldControl == 0x01)) {
+            vector<uint8_t>::const_iterator first = mFilterOutputs[filterId].begin() + i + 4;
+            vector<uint8_t>::const_iterator last = mFilterOutputs[filterId].begin() + i + 187;
+            vector<uint8_t> filterOutData(first, last);
+            if (!writeDataToFilterMQ(filterOutData, filterId)) {
+                mFilterOutputs[filterId].clear();
+                return Result::INVALID_STATE;
+            }
+            pesEvent = {
+                    // temp dump meta data
+                    .streamId = filterOutData[3],
+                    .dataLength = static_cast<uint16_t>(filterOutData.size()),
+            };
+            int size = mFilterEvents[filterId].events.size();
+            mFilterEvents[filterId].events.resize(size + 1);
+            mFilterEvents[filterId].events[size].pes(pesEvent);
+        }
     }
 
-    mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
+    mFilterOutputs[filterId].clear();
+
     return Result::SUCCESS;
 }
 
@@ -451,6 +506,8 @@
     };
     mFilterEvents[filterId].events.resize(1);
     mFilterEvents[filterId].events[0].media() = mediaEvent;
+
+    mFilterOutputs[filterId].clear();
     // TODO handle write FQM for media stream
     return Result::SUCCESS;
 }
@@ -465,6 +522,8 @@
     recordEvent.indexMask.tsIndexMask() = 0x01;
     mFilterEvents[filterId].events.resize(1);
     mFilterEvents[filterId].events[0].ts() = recordEvent;
+
+    mFilterOutputs[filterId].clear();
     return Result::SUCCESS;
 }
 
@@ -499,18 +558,18 @@
 bool Demux::writeSectionsAndCreateEvent(uint32_t filterId, vector<uint8_t> data) {
     // TODO check how many sections has been read
     std::lock_guard<std::mutex> lock(mFilterEventLock);
-    int size = mFilterEvents[filterId].events.size();
-    mFilterEvents[filterId].events.resize(size + 1);
     if (!writeDataToFilterMQ(data, filterId)) {
         return false;
     }
+    int size = mFilterEvents[filterId].events.size();
+    mFilterEvents[filterId].events.resize(size + 1);
     DemuxFilterSectionEvent secEvent;
     secEvent = {
             // temp dump meta data
             .tableId = 0,
             .version = 1,
             .sectionNum = 1,
-            .dataLength = 530,
+            .dataLength = static_cast<uint16_t>(data.size()),
     };
     mFilterEvents[filterId].events[size].section(secEvent);
     return true;
@@ -524,21 +583,44 @@
     return false;
 }
 
-bool Demux::filterAndOutputData() {
-    ALOGD("[Demux] start to dispatch data to filters");
+bool Demux::readInputFMQ() {
     // Read input data from the input FMQ
     int size = mInputMQ->availableToRead();
+    int inputPacketSize = mInputSettings.packetSize;
     vector<uint8_t> dataOutputBuffer;
-    dataOutputBuffer.resize(size);
-    mInputMQ->read(dataOutputBuffer.data(), size);
+    dataOutputBuffer.resize(inputPacketSize);
 
-    Result result;
-    // Filter the data and feed the output to each filter
+    // Dispatch the packet to the PID matching filter output buffer
+    for (int i = 0; i < size / inputPacketSize; i++) {
+        if (!mInputMQ->read(dataOutputBuffer.data(), inputPacketSize)) {
+            return false;
+        }
+        startTsFilter(dataOutputBuffer);
+    }
+
+    return true;
+}
+
+void Demux::startTsFilter(vector<uint8_t> data) {
     set<uint32_t>::iterator it;
     for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
+        uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
+        ALOGW("start ts filter pid: %d", pid);
+        if (pid == mFilterPids[*it]) {
+            mFilterOutputs[*it].insert(mFilterOutputs[*it].end(), data.begin(), data.end());
+        }
+    }
+}
+
+bool Demux::startFilterDispatcher() {
+    Result result;
+    set<uint32_t>::iterator it;
+
+    // Handle the output data per filter type
+    for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
         switch (mFilterEvents[*it].filterType) {
             case DemuxFilterType::SECTION:
-                result = startSectionFilterHandler(*it, dataOutputBuffer);
+                result = startSectionFilterHandler(*it);
                 break;
             case DemuxFilterType::PES:
                 result = startPesFilterHandler(*it);
@@ -578,6 +660,7 @@
 
 void Demux::filterThreadLoop(uint32_t filterId) {
     ALOGD("[Demux] filter %d threadLoop start.", filterId);
+    std::lock_guard<std::mutex> lock(mFilterThreadLock);
     mFilterThreadRunning[filterId] = true;
 
     // For the first time of filter output, implementation needs to send the filter
@@ -640,6 +723,7 @@
 
 void Demux::inputThreadLoop() {
     ALOGD("[Demux] input threadLoop start.");
+    std::lock_guard<std::mutex> lock(mInputThreadLock);
     mInputThreadRunning = true;
 
     while (mInputThreadRunning) {
@@ -651,18 +735,112 @@
             ALOGD("[Demux] wait for data ready on the input FMQ");
             continue;
         }
-        // Our current implementation filter the data and write it into the filter FMQ immedaitely
+        // Our current implementation filter the data and write it into the filter FMQ immediately
         // after the DATA_READY from the VTS/framework
-        if (!filterAndOutputData()) {
+        if (!readInputFMQ() || !startFilterDispatcher()) {
             ALOGD("[Demux] input data failed to be filtered. Ending thread");
             break;
         }
+
+        maySendInputStatusCallback();
     }
 
     mInputThreadRunning = false;
     ALOGD("[Demux] input thread ended.");
 }
 
+void Demux::maySendInputStatusCallback() {
+    std::lock_guard<std::mutex> lock(mInputStatusLock);
+    int availableToRead = mInputMQ->availableToRead();
+    int availableToWrite = mInputMQ->availableToWrite();
+
+    DemuxInputStatus newStatus =
+            checkStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold,
+                              mInputSettings.lowThreshold);
+    if (mIntputStatus != newStatus) {
+        mInputCallback->onInputStatus(newStatus);
+        mIntputStatus = newStatus;
+    }
+}
+
+DemuxInputStatus Demux::checkStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                          uint32_t highThreshold, uint32_t lowThreshold) {
+    if (availableToWrite == 0) {
+        return DemuxInputStatus::SPACE_FULL;
+    } else if (availableToRead > highThreshold) {
+        return DemuxInputStatus::SPACE_ALMOST_FULL;
+    } else if (availableToRead < lowThreshold) {
+        return DemuxInputStatus::SPACE_ALMOST_EMPTY;
+    } else if (availableToRead == 0) {
+        return DemuxInputStatus::SPACE_EMPTY;
+    }
+    return mIntputStatus;
+}
+
+Result Demux::startBroadcastInputLoop() {
+    pthread_create(&mBroadcastInputThread, NULL, __threadLoopBroadcast, this);
+    pthread_setname_np(mBroadcastInputThread, "broadcast_input_thread");
+
+    return Result::SUCCESS;
+}
+
+void* Demux::__threadLoopBroadcast(void* user) {
+    Demux* const self = static_cast<Demux*>(user);
+    self->broadcastInputThreadLoop();
+    return 0;
+}
+
+void Demux::broadcastInputThreadLoop() {
+    std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
+    mBroadcastInputThreadRunning = true;
+    mKeepFetchingDataFromFrontend = true;
+
+    // open the stream and get its length
+    std::ifstream inputData(mFrontendSourceFile, std::ifstream::binary);
+    // TODO take the packet size from the frontend setting
+    int packetSize = 188;
+    int writePacketAmount = 6;
+    char* buffer = new char[packetSize];
+    ALOGW("[Demux] broadcast input thread loop start %s", mFrontendSourceFile.c_str());
+    if (!inputData.is_open()) {
+        mBroadcastInputThreadRunning = false;
+        ALOGW("[Demux] Error %s", strerror(errno));
+    }
+
+    while (mBroadcastInputThreadRunning) {
+        // move the stream pointer for packet size * 6 every read until the end
+        while (mKeepFetchingDataFromFrontend) {
+            for (int i = 0; i < writePacketAmount; i++) {
+                inputData.read(buffer, packetSize);
+                if (!inputData) {
+                    mBroadcastInputThreadRunning = false;
+                    break;
+                }
+                // filter and dispatch filter output
+                vector<uint8_t> byteBuffer;
+                byteBuffer.resize(sizeof(buffer));
+                for (int index = 0; index < byteBuffer.size(); index++) {
+                    byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
+                }
+                startTsFilter(byteBuffer);
+                inputData.seekg(packetSize, inputData.cur);
+            }
+            startFilterDispatcher();
+            sleep(1);
+        }
+    }
+
+    ALOGW("[Demux] Broadcast Input thread end.");
+    delete[] buffer;
+    inputData.close();
+}
+
+void Demux::stopBroadcastInput() {
+    mKeepFetchingDataFromFrontend = false;
+    mBroadcastInputThreadRunning = false;
+    std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index 2fdde8d..e4a4e2b 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -20,6 +20,8 @@
 #include <android/hardware/tv/tuner/1.0/IDemux.h>
 #include <fmq/MessageQueue.h>
 #include <set>
+#include "Frontend.h"
+#include "Tuner.h"
 
 using namespace std;
 
@@ -40,9 +42,12 @@
 
 using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
 
+class Tuner;
+class Frontend;
+
 class Demux : public IDemux {
   public:
-    Demux(uint32_t demuxId);
+    Demux(uint32_t demuxId, sp<Tuner> tuner);
 
     ~Demux();
 
@@ -91,9 +96,9 @@
 
     virtual Return<Result> configureOutput(const DemuxOutputSettings& settings) override;
 
-    virtual Return<Result> attachOutputTsFilter(uint32_t filterId) override;
+    virtual Return<Result> attachOutputFilter(uint32_t filterId) override;
 
-    virtual Return<Result> detachOutputTsFilter(uint32_t filterId) override;
+    virtual Return<Result> detachOutputFilter(uint32_t filterId) override;
 
     virtual Return<Result> startOutput() override;
 
@@ -103,7 +108,17 @@
 
     virtual Return<Result> removeOutput() override;
 
+    // Functions interacts with Tuner Service
+    void stopBroadcastInput();
+
   private:
+    // Tuner service
+    sp<Tuner> mTunerService;
+
+    // Frontend source
+    sp<Frontend> mFrontend;
+    string mFrontendSourceFile;
+
     // A struct that passes the arguments to a newly created filter thread
     struct ThreadArgs {
         Demux* user;
@@ -115,13 +130,14 @@
      * They are also responsible to write the filtered output into the filter FMQ
      * and update the filterEvent bound with the same filterId.
      */
-    Result startSectionFilterHandler(uint32_t filterId, vector<uint8_t> data);
+    Result startSectionFilterHandler(uint32_t filterId);
     Result startPesFilterHandler(uint32_t filterId);
     Result startTsFilterHandler();
     Result startMediaFilterHandler(uint32_t filterId);
     Result startRecordFilterHandler(uint32_t filterId);
     Result startPcrFilterHandler();
     Result startFilterLoop(uint32_t filterId);
+    Result startBroadcastInputLoop();
 
     /**
      * To create a FilterMQ with the the next available Filter ID.
@@ -136,18 +152,24 @@
     bool writeDataToFilterMQ(const std::vector<uint8_t>& data, uint32_t filterId);
     bool readDataFromMQ();
     bool writeSectionsAndCreateEvent(uint32_t filterId, vector<uint8_t> data);
+    void maySendInputStatusCallback();
+    DemuxInputStatus checkStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                       uint32_t highThreshold, uint32_t lowThreshold);
     /**
      * A dispatcher to read and dispatch input data to all the started filters.
      * Each filter handler handles the data filtering/output writing/filterEvent updating.
      */
-    bool filterAndOutputData();
+    bool readInputFMQ();
+    void startTsFilter(vector<uint8_t> data);
+    bool startFilterDispatcher();
     static void* __threadLoopFilter(void* data);
     static void* __threadLoopInput(void* user);
+    static void* __threadLoopBroadcast(void* user);
     void filterThreadLoop(uint32_t filterId);
     void inputThreadLoop();
+    void broadcastInputThreadLoop();
 
     uint32_t mDemuxId;
-    uint32_t mSourceFrontendId;
     /**
      * Record the last used filter id. Initial value is -1.
      * Filter Id starts with 0.
@@ -169,6 +191,8 @@
      * A list of created FilterMQ ptrs.
      * The array number is the filter ID.
      */
+    vector<uint16_t> mFilterPids;
+    vector<vector<uint8_t>> mFilterOutputs;
     vector<unique_ptr<FilterMQ>> mFilterMQs;
     vector<EventFlag*> mFilterEventFlags;
     vector<DemuxFilterEvent> mFilterEvents;
@@ -182,15 +206,26 @@
     vector<sp<IDemuxCallback>> mDemuxCallbacks;
     sp<IDemuxCallback> mInputCallback;
     sp<IDemuxCallback> mOutputCallback;
+    bool mInputConfigured = false;
+    bool mOutputConfigured = false;
+    DemuxInputSettings mInputSettings;
+    DemuxOutputSettings mOutputSettings;
+
     // Thread handlers
     pthread_t mInputThread;
     pthread_t mOutputThread;
+    pthread_t mBroadcastInputThread;
     vector<pthread_t> mFilterThreads;
+
+    // FMQ status local records
+    DemuxInputStatus mIntputStatus;
     /**
      * If a specific filter's writing loop is still running
      */
     vector<bool> mFilterThreadRunning;
     bool mInputThreadRunning;
+    bool mBroadcastInputThreadRunning;
+    bool mKeepFetchingDataFromFrontend;
     /**
      * Lock to protect writes to the FMQs
      */
@@ -198,8 +233,16 @@
     /**
      * Lock to protect writes to the filter event
      */
+    // TODO make each filter separate event lock
     std::mutex mFilterEventLock;
     /**
+     * Lock to protect writes to the input status
+     */
+    std::mutex mInputStatusLock;
+    std::mutex mBroadcastInputThreadLock;
+    std::mutex mFilterThreadLock;
+    std::mutex mInputThreadLock;
+    /**
      * How many times a filter should write
      * TODO make this dynamic/random/can take as a parameter
      */
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 0609d05..1e07edd 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -27,14 +27,10 @@
 namespace V1_0 {
 namespace implementation {
 
-Frontend::Frontend() {
-    // Init callback to nullptr
-    mCallback = nullptr;
-}
-
-Frontend::Frontend(FrontendType type, FrontendId id) {
+Frontend::Frontend(FrontendType type, FrontendId id, sp<Tuner> tuner) {
     mType = type;
     mId = id;
+    mTunerService = tuner;
     // Init callback to nullptr
     mCallback = nullptr;
 }
@@ -67,13 +63,18 @@
         return Result::INVALID_STATE;
     }
 
-    mCallback->onEvent(FrontendEventType::NO_SIGNAL);
+    // TODO dynamically allocate file to the source file
+    mSourceStreamFile = FRONTEND_STREAM_FILE;
+
+    mCallback->onEvent(FrontendEventType::LOCKED);
     return Result::SUCCESS;
 }
 
 Return<Result> Frontend::stopTune() {
     ALOGV("%s", __FUNCTION__);
 
+    mTunerService->frontendStopTune(mId);
+
     return Result::SUCCESS;
 }
 
@@ -105,13 +106,7 @@
     return Result::SUCCESS;
 }
 
-Return<Result> Frontend::setLnb(const sp<ILnb>& /* lnb */) {
-    ALOGV("%s", __FUNCTION__);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Frontend::sendDiseqcMessage(const hidl_vec<uint8_t>& /* diseqcMessage */) {
+Return<Result> Frontend::setLnb(uint32_t /* lnb */) {
     ALOGV("%s", __FUNCTION__);
 
     return Result::SUCCESS;
@@ -125,6 +120,10 @@
     return mId;
 }
 
+string Frontend::getSourceFile() {
+    return mSourceStreamFile;
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h
index fc586b5..07fa7b9 100644
--- a/tv/tuner/1.0/default/Frontend.h
+++ b/tv/tuner/1.0/default/Frontend.h
@@ -18,7 +18,9 @@
 #define ANDROID_HARDWARE_TV_TUNER_V1_0_FRONTEND_H_
 
 #include <android/hardware/tv/tuner/1.0/IFrontend.h>
-#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <fstream>
+#include <iostream>
+#include "Tuner.h"
 
 using namespace std;
 
@@ -35,11 +37,11 @@
 using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
 using ::android::hardware::tv::tuner::V1_0::Result;
 
+class Tuner;
+
 class Frontend : public IFrontend {
   public:
-    Frontend();
-
-    Frontend(FrontendType type, FrontendId id);
+    Frontend(FrontendType type, FrontendId id, sp<Tuner> tuner);
 
     virtual Return<Result> close() override;
 
@@ -56,21 +58,26 @@
     virtual Return<void> getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
                                    getStatus_cb _hidl_cb) override;
 
-    virtual Return<Result> sendDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override;
-
     virtual Return<Result> setLna(bool bEnable) override;
 
-    virtual Return<Result> setLnb(const sp<ILnb>& lnb) override;
+    virtual Return<Result> setLnb(uint32_t lnb) override;
 
     FrontendType getFrontendType();
 
     FrontendId getFrontendId();
 
+    string getSourceFile();
+
   private:
     virtual ~Frontend();
     sp<IFrontendCallback> mCallback;
+    sp<Tuner> mTunerService;
     FrontendType mType = FrontendType::UNDEFINED;
     FrontendId mId = 0;
+
+    const string FRONTEND_STREAM_FILE = "/vendor/etc/test1.ts";
+    string mSourceStreamFile;
+    std::ifstream mFrontendData;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp
index b81bb15..1446f7f 100644
--- a/tv/tuner/1.0/default/Lnb.cpp
+++ b/tv/tuner/1.0/default/Lnb.cpp
@@ -48,6 +48,12 @@
     return Result::SUCCESS;
 }
 
+Return<Result> Lnb::sendDiseqcMessage(const hidl_vec<uint8_t>& /* diseqcMessage */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
 Return<Result> Lnb::close() {
     ALOGV("%s", __FUNCTION__);
 
diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h
index df7e0fe..4c251f7 100644
--- a/tv/tuner/1.0/default/Lnb.h
+++ b/tv/tuner/1.0/default/Lnb.h
@@ -38,12 +38,14 @@
   public:
     Lnb();
 
-    virtual Return<Result> setVoltage(FrontendLnbVoltage voltage);
+    virtual Return<Result> setVoltage(FrontendLnbVoltage voltage) override;
 
     virtual Return<Result> setTone(FrontendLnbTone tone) override;
 
     virtual Return<Result> setSatellitePosition(FrontendLnbPosition position) override;
 
+    virtual Return<Result> sendDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override;
+
     virtual Return<Result> close() override;
 
   private:
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index 00831ae..f86b28d 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -38,14 +38,14 @@
     // Array index matches their FrontendId in the default impl
     mFrontendSize = 8;
     mFrontends.resize(mFrontendSize);
-    mFrontends[0] = new Frontend();
-    mFrontends[1] = new Frontend(FrontendType::ATSC, 1);
-    mFrontends[2] = new Frontend(FrontendType::DVBC, 2);
-    mFrontends[3] = new Frontend(FrontendType::DVBS, 3);
-    mFrontends[4] = new Frontend(FrontendType::DVBT, 4);
-    mFrontends[5] = new Frontend(FrontendType::ISDBT, 5);
-    mFrontends[6] = new Frontend(FrontendType::ANALOG, 6);
-    mFrontends[7] = new Frontend(FrontendType::ATSC, 7);
+    mFrontends[0] = new Frontend(FrontendType::DVBT, 0, this);
+    mFrontends[1] = new Frontend(FrontendType::ATSC, 1, this);
+    mFrontends[2] = new Frontend(FrontendType::DVBC, 2, this);
+    mFrontends[3] = new Frontend(FrontendType::DVBS, 3, this);
+    mFrontends[4] = new Frontend(FrontendType::DVBT, 4, this);
+    mFrontends[5] = new Frontend(FrontendType::ISDBT, 5, this);
+    mFrontends[6] = new Frontend(FrontendType::ANALOG, 6, this);
+    mFrontends[7] = new Frontend(FrontendType::ATSC, 7, this);
 }
 
 Tuner::~Tuner() {}
@@ -81,12 +81,22 @@
 
     DemuxId demuxId = mLastUsedId + 1;
     mLastUsedId += 1;
-    sp<IDemux> demux = new Demux(demuxId);
+    sp<Demux> demux = new Demux(demuxId, this);
+    mDemuxes[demuxId] = demux;
 
     _hidl_cb(Result::SUCCESS, demuxId, demux);
     return Void();
 }
 
+Return<void> Tuner::getDemuxCaps(getDemuxCaps_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    DemuxCapabilities caps;
+
+    _hidl_cb(Result::SUCCESS, caps);
+    return Void();
+}
+
 Return<void> Tuner::openDescrambler(openDescrambler_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
@@ -123,6 +133,25 @@
     return Void();
 }
 
+sp<Frontend> Tuner::getFrontendById(uint32_t frontendId) {
+    ALOGV("%s", __FUNCTION__);
+
+    return mFrontends[frontendId];
+}
+
+void Tuner::setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId) {
+    mFrontendToDemux[frontendId] = demuxId;
+}
+
+void Tuner::frontendStopTune(uint32_t frontendId) {
+    map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
+    uint32_t demuxId;
+    if (it != mFrontendToDemux.end()) {
+        demuxId = it->second;
+        mDemuxes[demuxId]->stopBroadcastInput();
+    }
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
index 62227ee..96da257 100644
--- a/tv/tuner/1.0/default/Tuner.h
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -18,6 +18,8 @@
 #define ANDROID_HARDWARE_TV_TUNER_V1_0_TUNER_H_
 
 #include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <map>
+#include "Demux.h"
 #include "Frontend.h"
 
 using namespace std;
@@ -29,6 +31,9 @@
 namespace V1_0 {
 namespace implementation {
 
+class Frontend;
+class Demux;
+
 class Tuner : public ITuner {
   public:
     Tuner();
@@ -39,6 +44,8 @@
 
     virtual Return<void> openDemux(openDemux_cb _hidl_cb) override;
 
+    virtual Return<void> getDemuxCaps(getDemuxCaps_cb _hidl_cb) override;
+
     virtual Return<void> openDescrambler(openDescrambler_cb _hidl_cb) override;
 
     virtual Return<void> getFrontendInfo(FrontendId frontendId,
@@ -48,10 +55,18 @@
 
     virtual Return<void> openLnbById(LnbId lnbId, openLnbById_cb _hidl_cb) override;
 
+    sp<Frontend> getFrontendById(uint32_t frontendId);
+
+    void setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId);
+
+    void frontendStopTune(uint32_t frontendId);
+
   private:
     virtual ~Tuner();
     // Static mFrontends array to maintain local frontends information
     vector<sp<Frontend>> mFrontends;
+    std::map<uint32_t, uint32_t> mFrontendToDemux;
+    std::map<uint32_t, sp<Demux>> mDemuxes;
     // To maintain how many Frontends we have
     int mFrontendSize;
     // The last used demux id. Initial value is -1.
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index d37f63a..890c1ed 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -43,7 +43,7 @@
     ANALOG,
     /* Advanced Television Systems Committee (ATSC) Standard A/72. */
     ATSC,
-    /* Advanced Television Systems Committee (ATSC 3.0) Standard A/330. */
+    /* Advanced Television Systems Committee (ATSC 3.0) Standard A/300. */
     ATSC3,
     /**
      * Digital Video Broadcasting - Cable
@@ -58,16 +58,16 @@
     DVBS,
     /**
      * Digital Video Broadcasting - Terrestrial
-     * DVB Terresttrial Frontend Standard ETSI EN 300 468 V1.15.1 and
+     * DVB Terrestrial Frontend Standard ETSI EN 300 468 V1.15.1 and
      * ETSI EN 302 755 V1.4.1.
      */
     DVBT,
     /* Integrated Services Digital Broadcasting-Satellite (ISDB-S)
-     * ARIB SDT-B20 is technical document of ISDB-S.
+     * ARIB STD-B20 is technical document of ISDB-S.
      */
     ISDBS,
     /* Integrated Services Digital Broadcasting-Satellite (ISDB-S)
-     * ARIB TR-B15 is technical document of ISDB-S3.
+     * ARIB STD-B44 is technical document of ISDB-S3.
      */
     ISDBS3,
     /* Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD)
@@ -164,8 +164,10 @@
 @export
 enum FrontendAtscModulation : uint32_t {
     UNDEFINED = 0,
-    MOD_8VSB = 1 << 0,
-    MOD_16VSB = 1 << 1,
+    /** hardware is able to detect and set modulation automatically */
+    AUTO      = 1 << 0,
+    MOD_8VSB  = 1 << 2,
+    MOD_16VSB = 1 << 3,
 };
 
 /**
@@ -191,12 +193,14 @@
 @export
 enum FrontendAtsc3Modulation : uint32_t {
     UNDEFINED = 0,
-    MOD_QPSK = 1 << 0,
-    MOD_16QAM = 1 << 1,
-    MOD_64QAM = 1 << 2,
-    MOD_256QAM = 1 << 3,
-    MOD_1024QAM = 1 << 4,
-    MOD_4096QAM = 1 << 5,
+    /** hardware is able to detect and set modulation automatically */
+    AUTO        = 1 << 0,
+    MOD_QPSK    = 1 << 1,
+    MOD_16QAM   = 1 << 2,
+    MOD_64QAM   = 1 << 3,
+    MOD_256QAM  = 1 << 4,
+    MOD_1024QAM = 1 << 5,
+    MOD_4096QAM = 1 << 6,
 };
 
 /**
@@ -205,9 +209,11 @@
 @export
 enum FrontendAtsc3Bandwidth : uint32_t {
     UNDEFINED = 0,
-    BANDWIDTH_8MHZ = 1 << 0,
-    BANDWIDTH_7MHZ = 1 << 1,
-    BANDWIDTH_6MHZ = 1 << 2,
+    /** hardware is able to detect and set bandwidth automatically */
+    AUTO = 1 << 0,
+    BANDWIDTH_6MHZ = 1 << 1,
+    BANDWIDTH_7MHZ = 1 << 2,
+    BANDWIDTH_8MHZ = 1 << 3,
 };
 
 /**
@@ -215,9 +221,11 @@
  */
 @export
 enum FrontendAtsc3TimeInterleaveMode : uint32_t {
-    UNDEFINED,
-    CTI,
-    HTI,
+    UNDEFINED = 0,
+    /** hardware is able to detect and set TimeInterleaveMode automatically */
+    AUTO = 1 << 0,
+    CTI  = 1 << 1,
+    HTI  = 1 << 2,
 };
 
 /**
@@ -247,13 +255,39 @@
  */
 @export
 enum FrontendAtsc3Fec : uint32_t {
-    UNDEFINED,
-    BCH_LDPC_16K,
-    BCH_LDPC_64K,
-    CRC_LDPC_16K,
-    CRC_LDPC_64K,
-    LDPC_16K,
-    LDPC_64K,
+    UNDEFINED = 0,
+    /** hardware is able to detect and set FEC automatically */
+    AUTO     = 1 << 0,
+    BCH_LDPC_16K = 1 << 1,
+    BCH_LDPC_64K = 1 << 2,
+    CRC_LDPC_16K = 1 << 3,
+    CRC_LDPC_64K = 1 << 4,
+    LDPC_16K     = 1 << 5,
+    LDPC_64K     = 1 << 6,
+};
+
+/**
+ *  Demodulator Output Format for an ATSC3 Frontend.
+ */
+@export
+enum FrontendAtsc3DemodOutputFormat : uint8_t {
+    /** Dummy. Scan uses this. */
+    UNDEFINED = 0,
+    /** ALP format. Typically used in US region. */
+    ATSC3_LINKLAYER_PACKET = 1 << 0,
+    /** BaseBand packet format. Typically used in Korea region. */
+    BASEBAND_PACKET        = 1 << 1,
+};
+
+/**
+ *  PLP basis Signal Settings for an ATSC3 Frontend.
+ */
+struct FrontendAtsc3PlpSettings {
+    uint8_t plpId;
+    FrontendAtsc3Modulation modulation;
+    FrontendAtsc3TimeInterleaveMode interleaveMode;
+    FrontendAtsc3CodeRate codeRate;
+    FrontendAtsc3Fec fec;
 };
 
 /**
@@ -262,21 +296,28 @@
 struct FrontendAtsc3Settings {
     /** Signal frequency in Hertz */
     uint32_t frequency;
+    /** Bandwidth of tuning band. */
     FrontendAtsc3Bandwidth bandwidth;
-    FrontendAtsc3TimeInterleaveMode interleaveMode;
-    FrontendAtsc3CodeRate codeRate;
-    FrontendAtsc3Fec fec;
-    vec<uint8_t> plpIdList;
+    FrontendAtsc3DemodOutputFormat demodOutputFormat;
+    vec<FrontendAtsc3PlpSettings> plpSettings;
 };
 
 /**
  *  Capabilities for ATSC3 Frontend.
  */
 struct FrontendAtsc3Capabilities {
-    /** Modulation capability */
-    bitfield<FrontendAtsc3Modulation> modulationCap;
     /** Bandwidth capability */
     bitfield<FrontendAtsc3Bandwidth> bandwidthCap;
+    /** Modulation capability */
+    bitfield<FrontendAtsc3Modulation> modulationCap;
+    /** TimeInterleaveMode capability */
+    bitfield<FrontendAtsc3TimeInterleaveMode> timeInterleaveModeCap;
+    /** CodeRate capability */
+    bitfield<FrontendAtsc3CodeRate> codeRateCap;
+    /** FEC capability */
+    bitfield<FrontendAtsc3Fec> fecCap;
+    /** Demodulator Output Format capability */
+    bitfield<FrontendAtsc3DemodOutputFormat> demodOutputFormatCap;
 };
 
 /**
@@ -614,7 +655,7 @@
 };
 
 /**
- *  Modulaltion Type for ISDBS.
+ *  Modulation Type for ISDBS.
  */
 @export
 enum FrontendIsdbsModulation : uint32_t {
@@ -647,7 +688,7 @@
 @export
 enum FrontendIsdbsStreamIdType : uint32_t {
     STREAM_ID,
-    RELATIVE_STREAM_ID,
+    RELATIVE_STREAM_NUMBER,
 };
 
 /**
@@ -845,6 +886,7 @@
     M_EIA_J = 1 << 13,
     I_NICAM = 1 << 14,
     L_NICAM = 1 << 15,
+    L_PRIME = 1 << 16,
 };
 
 /**
@@ -907,17 +949,27 @@
     PLP_IDS,
     /** Locked group Ids for DVBT2 frontend. */
     GROUP_IDS,
-    /** Locked the number of the Plps. */
-   INPUT_STREAM_IDS,
-    /** Locked signal stardard.  */
+    /** Stream Ids. */
+    INPUT_STREAM_IDS,
+    /** Locked signal standard.  */
     STANDARD,
+    /** PLP status in a tuned frequency band for ATSC3 frontend. */
+    ATSC3_PLP_INFO,
+};
+
+/**
+ *  ATSC3.0 PLP information for scan
+ */
+struct FrontendScanAtsc3PlpInfo {
+    uint8_t plpId;
+    bool bLlsFlag;
 };
 
 /**
  *  Scan Message for Frontend.
  */
 safe_union FrontendScanMessage {
-    bool islocked;
+    bool isLocked;
     bool isEnd;
     /** scan progress percent (0..100) */
     uint8_t progressPercent;
@@ -927,11 +979,13 @@
     uint32_t symbolRate;
     vec<uint8_t> plpIds;
     vec<uint8_t> groupIds;
-    vec<uint8_t> inputStreamIds;
+    vec<uint16_t> inputStreamIds;
     safe_union standard {
         FrontendDvbsStandard sStd;
         FrontendDvbtStandard tStd;
     } std;
+    /** A list of PLP status in a tuned frequency band for ATSC3 frontend. */
+    vec<FrontendScanAtsc3PlpInfo> atsc3PlpInfos;
 };
 
 /**
@@ -940,17 +994,17 @@
 @export
 enum FrontendEventType : uint32_t {
     /**
-     * If frontend locked the signal which is specified by tune method, HAL sent
+     * If frontend locked the signal which is specified by tune method, HAL sends
      * Locked event.
      */
     LOCKED,
     /**
      * If frontend can't locked the signal which is specified by tune method,
-     * HAL sent NO_SIGNAL event.
+     * HAL sends NO_SIGNAL event.
      */
     NO_SIGNAL,
     /**
-     * If frontend detect that the locked signal get lost, HAL sent LOST_LOCK
+     * If frontend detect that the locked signal get lost, HAL sends LOST_LOCK
      * event.
      */
     LOST_LOCK,
@@ -977,15 +1031,15 @@
  */
 @export
 enum FrontendStatusType : uint32_t {
-    /** Lock status for RF or Demod. */
-    LOCK,
+    /** Lock status for Demod. */
+    DEMOD_LOCK,
     /** Signal to Noise Ratio. */
     SNR,
     /** Bit Error Ratio. */
     BER,
     /** Packages Error Ratio. */
     PER,
-    /** Bit Error Ratio befor FEC. */
+    /** Bit Error Ratio before FEC. */
     PRE_BER,
     /*
      * Signal Quality (0..100). Good data over total data in percent can be
@@ -993,7 +1047,7 @@
      */
     SIGNAL_QUALITY,
     /** Signal Strength. */
-    SIGGAL_STRENGTH,
+    SIGNAL_STRENGTH,
     /** Symbol Rate. */
     SYMBOL_RATE,
     /** Forward Error Correction Type. */
@@ -1008,21 +1062,62 @@
     PLP_ID,
     /** Status for Emergency Warning Broadcasting System. */
     EWBS,
+    /** Automatic Gain Control. */
+    AGC,
+    /** Low Noise Amplifier. */
+    LNA,
+    /** Lock status for stream. */
+    STREAM_LOCK,
+    /** Error status by layer. */
+    LAYER_ERROR,
+    /** CN value by VBER. */
+    VBER_CN,
+    /** CN value by LBER. */
+    LBER_CN,
+    /** CN value by XER. */
+    XER_CN,
+    /** Moduration Error Ratio. */
+    MER,
+    /** Difference between tuning frequency and actual locked frequency. */
+    FREQ_OFFSET,
+    /* Hierarchy for DVBT. */
+    HIERARCHY,
+    /** Lock status for RF. */
+    RF_LOCK,
+    /** PLP information in a frequency band for ATSC3.0 frontend. */
+    ATSC3_PLP_INFO,
 };
 
 /**
+ * Status for each tuning PLPs
+ */
+struct FrontendStatusAtsc3PlpInfo {
+    /** PLP Id value. */
+    uint8_t plpId;
+    /** Demod Lock/Unlock status of this particular PLP. */
+    bool isLocked;
+    /** Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation. */
+    uint32_t uec;
+};
+
+
+/**
  * Modulation Type for Frontend's status.
  */
 safe_union FrontendModulationStatus {
+    FrontendDvbcModulation dvbc;
     FrontendDvbsModulation dvbs;
-    FrontendAtsc3Modulation atsc3;
+    FrontendIsdbsModulation isdbs;
+    FrontendIsdbs3Modulation isdbs3;
+    FrontendIsdbtModulation isdbt;
 };
 
 /**
  *  The status for Frontend.
  */
 safe_union FrontendStatus {
-    bool isLocked;
+    /** Lock status for Demod in True/False. */
+    bool isDemodLocked;
     /** SNR value measured by 0.001 dB. */
     int32_t snr;
     /** The number of error bit per 1 billion bits. */
@@ -1043,6 +1138,25 @@
     FrontendLnbVoltage lnbVoltage;
     uint8_t plpId;
     bool isEWBS;
+    /** AGC value is normalized from 0 to 255. */
+    uint8_t agc;
+    bool isLnaOn;
+    bool isStreamLock;
+    vec<bool> isLayerError;
+    /** CN value by VBER measured by 0.001 dB */
+    int32_t vberCn;
+    /** CN value by LBER measured by 0.001 dB */
+    int32_t lberCn;
+    /** CN value by XER measured by 0.001 dB */
+    int32_t xerCn;
+    /** MER value measured by 0.001 dB */
+    int32_t mer;
+    /** Frequency difference in Hertz. */
+    int32_t freqOffset;
+    FrontendDvbtHierarchy hierarchy;
+    bool isRfLocked;
+    /** A list of PLP status for tuned PLPs for ATSC3 frontend. */
+    vec<FrontendStatusAtsc3PlpInfo> plpInfo;
 };
 
 /**
@@ -1121,7 +1235,6 @@
     POSITION_B,
 };
 
-
 /* Demux ID is used to associate with a hardware demux resource. */
 typedef uint32_t DemuxId;
 
@@ -1150,7 +1263,7 @@
      */
     AUDIO,
     /**
-     * A filter to filter Vidoe Metadata out from input stream.
+     * A filter to filter Video Metadata out from input stream.
      */
     VIDEO,
     /**
@@ -1475,6 +1588,8 @@
     PES,
     /* Data is Elementary Stream. */
     ES,
+    /* Data is TLV (type-length-value) Stream for JP SHV */
+    SHV_TLV,
 };
 
 /**
@@ -1534,6 +1649,10 @@
     SPACE_FULL         = 1 << 3,
 };
 
+/**
+ *  The Settings for the demux's input.
+ */
+@export
 struct DemuxInputSettings {
     /**
      * Register for interested status events so that the HAL can send these
@@ -1559,3 +1678,30 @@
      */
     uint8_t packetSize;
 };
+
+/**
+ *  Capabilities for Demux.
+ */
+@export
+struct DemuxCapabilities {
+    /* The number of Demux to be supported. */
+    uint32_t numDemux;
+    /* The number of Input to be supported. */
+    uint32_t numInput;
+    /* The number of Output to be supported. */
+    uint32_t numOutput;
+    /* The number of TS Filter to be supported. */
+    uint32_t numTsFilter;
+    /* The number of Section Filter to be supported. */
+    uint32_t numSectionFilter;
+    /* The number of Audio Filter to be supported. */
+    uint32_t numAudioFilter;
+    /* The number of Video Filter to be supported. */
+    uint32_t numVideoFilter;
+    /* The number of PES Filter to be supported. */
+    uint32_t numPesFilter;
+    /* The number of PCR Filter to be supported. */
+    uint32_t numPcrFilter;
+    /* The maximum number of bytes is supported in the mask of Section Filter. */
+    uint32_t numBytesInSectionFilter;
+};
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 7256cc4..7936185 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -39,6 +39,7 @@
 #include <map>
 
 #define WAIT_TIMEOUT 3000000000
+#define WAIT_TIMEOUT_data_ready 3000000000 * 4
 
 using android::Condition;
 using android::IMemory;
@@ -58,8 +59,10 @@
 using android::hardware::Void;
 using android::hardware::tv::tuner::V1_0::DemuxDataFormat;
 using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
 using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
 using android::hardware::tv::tuner::V1_0::DemuxFilterType;
@@ -130,9 +133,6 @@
 
 const uint16_t FMQ_SIZE_4K = 0x1000;
 const uint32_t FMQ_SIZE_1M = 0x100000;
-// Equal to SECTION_WRITE_COUNT on the HAL impl side
-// The HAL impl will repeatedly write to the FMQ the count times
-const uint16_t SECTION_READ_COUNT = 10;
 
 struct FilterConf {
     DemuxFilterType type;
@@ -214,11 +214,15 @@
 class DemuxCallback : public IDemuxCallback {
   public:
     virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent) override {
-        ALOGW("[VTS] FILTER EVENT %d", filterEvent.filterId);
         android::Mutex::Autolock autoLock(mMsgLock);
-        mFilterEventReceived = true;
+        // Temprarily we treat the first coming back filter data on the matching pid a success
+        // once all of the MQ are cleared, means we got all the expected output
         mFilterIdToEvent[filterEvent.filterId] = filterEvent;
-        startFilterEventThread(filterEvent);
+        readFilterEventData(filterEvent.filterId);
+        mPidFilterOutputCount++;
+        // mFilterIdToMQ.erase(filterEvent.filterId);
+
+        // startFilterEventThread(filterEvent);
         mMsgCondition.signal();
         return Void();
     }
@@ -232,13 +236,16 @@
 
     virtual Return<void> onInputStatus(DemuxInputStatus status) override {
         // android::Mutex::Autolock autoLock(mMsgLock);
+        ALOGW("[vts] input status %d", status);
         switch (status) {
             case DemuxInputStatus::SPACE_EMPTY:
             case DemuxInputStatus::SPACE_ALMOST_EMPTY:
+                ALOGW("[vts] keep inputing %d", status);
                 mKeepWritingInputFMQ = true;
                 break;
             case DemuxInputStatus::SPACE_ALMOST_FULL:
             case DemuxInputStatus::SPACE_FULL:
+                ALOGW("[vts] stop inputing %d", status);
                 mKeepWritingInputFMQ = false;
                 break;
         }
@@ -246,78 +253,64 @@
     }
 
     void testOnFilterEvent(uint32_t filterId);
-    void testOnSectionFilterEvent(sp<IDemux>& demux, uint32_t filterId, MQDesc& filterMQDescriptor,
-                                  MQDesc& inputMQDescriptor);
     void testFilterDataOutput();
-    // Legacy
-    bool readAndCompareSectionEventData(uint32_t filterId);
+    void stopInputThread();
 
     void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor);
     void startFilterEventThread(DemuxFilterEvent event);
     static void* __threadLoopInput(void* threadArgs);
     static void* __threadLoopFilter(void* threadArgs);
-    void inputThreadLoop(InputConf inputConf, bool* keepWritingInputFMQ, MQDesc& inputMQDescriptor);
+    void inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ);
     void filterThreadLoop(DemuxFilterEvent& event);
 
     void updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor);
     void updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile);
+    bool readFilterEventData(uint32_t filterId);
 
   private:
     struct InputThreadArgs {
         DemuxCallback* user;
-        InputConf inputConf;
+        InputConf* inputConf;
         bool* keepWritingInputFMQ;
-        MQDesc& inputMQDesc;
     };
     struct FilterThreadArgs {
         DemuxCallback* user;
-        DemuxFilterEvent& event;
+        DemuxFilterEvent event;
     };
     uint16_t mDataLength = 0;
     std::vector<uint8_t> mDataOutputBuffer;
 
     bool mFilterEventReceived;
     std::map<uint32_t, string> mFilterIdToGoldenOutput;
-    std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
 
     std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
     std::unique_ptr<FilterMQ> mInputMQ;
     std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
+    std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
     EventFlag* mInputMQEventFlag;
 
     android::Mutex mMsgLock;
     android::Mutex mFilterOutputLock;
+    android::Mutex mInputThreadLock;
     android::Condition mMsgCondition;
     android::Condition mFilterOutputCondition;
 
-    bool mKeepWritingInputFMQ;
+    bool mKeepWritingInputFMQ = true;
     bool mInputThreadRunning;
     pthread_t mInputThread;
     pthread_t mFilterThread;
+
+    int mPidFilterOutputCount = 0;
 };
 
-// Legacy
-void DemuxCallback::testOnFilterEvent(uint32_t filterId) {
-    android::Mutex::Autolock autoLock(mMsgLock);
-    while (!mFilterEventReceived) {
-        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
-            EXPECT_TRUE(false) << "filter event not received within timeout";
-            return;
-        }
-    }
-    // Reset the filter event recieved flag
-    mFilterEventReceived = false;
-    // Check if filter id match
-    EXPECT_TRUE(filterId == mFilterIdToEvent[filterId].filterId) << "filter id match";
-}
-
 void DemuxCallback::startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor) {
+    mInputMQ = std::make_unique<FilterMQ>(inputMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mInputMQ);
     struct InputThreadArgs* threadArgs =
             (struct InputThreadArgs*)malloc(sizeof(struct InputThreadArgs));
     threadArgs->user = this;
-    threadArgs->inputConf = inputConf;
+    threadArgs->inputConf = &inputConf;
     threadArgs->keepWritingInputFMQ = &mKeepWritingInputFMQ;
-    threadArgs->inputMQDesc = inputMQDescriptor;
 
     pthread_create(&mInputThread, NULL, __threadLoopInput, (void*)threadArgs);
     pthread_setname_np(mInputThread, "test_playback_input_loop");
@@ -334,72 +327,22 @@
 }
 
 void DemuxCallback::testFilterDataOutput() {
-    android::Mutex::Autolock autoLock(mFilterOutputLock);
-    while (!mFilterIdToMQ.empty()) {
-        if (-ETIMEDOUT == mFilterOutputCondition.waitRelative(mFilterOutputLock, WAIT_TIMEOUT)) {
-            EXPECT_TRUE(false) << "filter output does not match golden output within timeout";
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (mPidFilterOutputCount < 1) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
             return;
         }
     }
+    mPidFilterOutputCount = 0;
+    ALOGW("[vts] pass and stop");
 }
 
-// Legacy
-void DemuxCallback::testOnSectionFilterEvent(sp<IDemux>& demux, uint32_t filterId,
-                                             MQDesc& filterMQDescriptor,
-                                             MQDesc& inputMQDescriptor) {
-    Result status;
-    // Create MQ to read the output into the local buffer
-    mFilterIdToMQ[filterId] =
-            std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
-    EXPECT_TRUE(mFilterIdToMQ[filterId]);
-    // Get the MQ to write the input to the HAL
-    mInputMQ = std::make_unique<FilterMQ>(inputMQDescriptor, true /* resetPointers */);
-    EXPECT_TRUE(mInputMQ);
-    // Create the EventFlag that is used to signal the HAL impl that data have been
-    // read the Filter FMQ
-    EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ[filterId]->getEventFlagWord(),
-                                           &mFilterIdToMQEventFlag[filterId]) == android::OK);
-    // Create the EventFlag that is used to signal the HAL impl that data have been
-    // written into the Input FMQ
-    EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &mInputMQEventFlag) ==
-                android::OK);
-    // Start filter
-    status = demux->startFilter(filterId);
-    status = demux->startInput();
+void DemuxCallback::stopInputThread() {
+    mInputThreadRunning = false;
+    mKeepWritingInputFMQ = false;
 
-    EXPECT_EQ(status, Result::SUCCESS);
-    // Test start filter and receive callback event
-    for (int i = 0; i < SECTION_READ_COUNT; i++) {
-        // Write input FMQ and notify the Tuner Implementation
-        EXPECT_TRUE(mInputMQ->write(goldenDataOutputBuffer.data(), goldenDataOutputBuffer.size()));
-        mInputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
-        testOnFilterEvent(filterId);
-        // checksum of mDataOutputBuffer and Input golden input
-        if (readAndCompareSectionEventData(filterId) && i < SECTION_READ_COUNT - 1) {
-            mFilterIdToMQEventFlag[filterId]->wake(
-                    static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
-        }
-    }
-}
-
-// Legacy
-bool DemuxCallback::readAndCompareSectionEventData(uint32_t filterId) {
-    bool result = false;
-    DemuxFilterEvent filterEvent = mFilterIdToEvent[filterId];
-    for (int i = 0; i < filterEvent.events.size(); i++) {
-        DemuxFilterSectionEvent event = filterEvent.events[i].section();
-        mDataLength = event.dataLength;
-        EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not match";
-
-        mDataOutputBuffer.resize(mDataLength);
-        result = mFilterIdToMQ[filterId]->read(mDataOutputBuffer.data(), mDataLength);
-        EXPECT_TRUE(result) << "can't read from Filter MQ";
-
-        for (int i = 0; i < mDataLength; i++) {
-            EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
-        }
-    }
-    return result;
+    android::Mutex::Autolock autoLock(mInputThreadLock);
 }
 
 void DemuxCallback::updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor) {
@@ -418,58 +361,60 @@
     DemuxCallback* const self =
             static_cast<DemuxCallback*>(((struct InputThreadArgs*)threadArgs)->user);
     self->inputThreadLoop(((struct InputThreadArgs*)threadArgs)->inputConf,
-                          ((struct InputThreadArgs*)threadArgs)->keepWritingInputFMQ,
-                          ((struct InputThreadArgs*)threadArgs)->inputMQDesc);
+                          ((struct InputThreadArgs*)threadArgs)->keepWritingInputFMQ);
     return 0;
 }
 
-void DemuxCallback::inputThreadLoop(InputConf inputConf, bool* keepWritingInputFMQ,
-                                    MQDesc& inputMQDescriptor) {
+void DemuxCallback::inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ) {
+    android::Mutex::Autolock autoLock(mInputThreadLock);
     mInputThreadRunning = true;
 
-    std::unique_ptr inputMQ =
-            std::make_unique<FilterMQ>(inputMQDescriptor, true /* resetPointers */);
-    EXPECT_TRUE(inputMQ);
-
     // Create the EventFlag that is used to signal the HAL impl that data have been
     // written into the Input FMQ
     EventFlag* inputMQEventFlag;
-    EXPECT_TRUE(EventFlag::createEventFlag(inputMQ->getEventFlagWord(), &inputMQEventFlag) ==
+    EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &inputMQEventFlag) ==
                 android::OK);
 
     // open the stream and get its length
-    std::ifstream inputData(inputConf.inputDataFile /*"ts/test1.ts"*/, std::ifstream::binary);
-    int writeSize = inputConf.setting.packetSize * 6;
+    std::ifstream inputData(inputConf->inputDataFile, std::ifstream::binary);
+    int writeSize = inputConf->setting.packetSize * 6;
     char* buffer = new char[writeSize];
-    if (!inputData) {
-        // log
+    ALOGW("[vts] input thread loop start %s", inputConf->inputDataFile.c_str());
+    if (!inputData.is_open()) {
         mInputThreadRunning = false;
+        ALOGW("[vts] Error %s", strerror(errno));
     }
 
     while (mInputThreadRunning) {
-        // move the stream pointer for packet size * 2k? every read until end
+        // move the stream pointer for packet size * 6 every read until the end
         while (*keepWritingInputFMQ) {
             inputData.read(buffer, writeSize);
             if (!inputData) {
                 int leftSize = inputData.gcount();
+                if (leftSize == 0) {
+                    mInputThreadRunning = false;
+                    break;
+                }
                 inputData.clear();
                 inputData.read(buffer, leftSize);
                 // Write the left over of the input data and quit the thread
                 if (leftSize > 0) {
-                    EXPECT_TRUE(inputMQ->write((unsigned char*)&buffer[0],
-                                               leftSize / inputConf.setting.packetSize));
+                    EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], leftSize));
                     inputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
                 }
                 mInputThreadRunning = false;
                 break;
             }
             // Write input FMQ and notify the Tuner Implementation
-            EXPECT_TRUE(inputMQ->write((unsigned char*)&buffer[0], 6));
+            EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], writeSize));
             inputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
             inputData.seekg(writeSize, inputData.cur);
+            sleep(1);
         }
     }
 
+    ALOGW("[vts] Input thread end.");
+
     delete[] buffer;
     inputData.close();
 }
@@ -481,9 +426,9 @@
     return 0;
 }
 
-void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /*event*/) {
+void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
     android::Mutex::Autolock autoLock(mFilterOutputLock);
-    // Read from MQ[event.filterId] per event and filter type
+    // Read from mFilterIdToMQ[event.filterId] per event and filter type
 
     // Assemble to filterOutput[filterId]
 
@@ -494,6 +439,30 @@
     // end thread
 }
 
+bool DemuxCallback::readFilterEventData(uint32_t filterId) {
+    bool result = false;
+    DemuxFilterEvent filterEvent = mFilterIdToEvent[filterId];
+    ALOGW("[vts] reading from filter FMQ %d", filterId);
+    // todo separate filter handlers
+    for (int i = 0; i < filterEvent.events.size(); i++) {
+        DemuxFilterPesEvent event = filterEvent.events[i].pes();
+        mDataLength = event.dataLength;
+        // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not
+        // match";
+
+        mDataOutputBuffer.resize(mDataLength);
+        result = mFilterIdToMQ[filterId]->read(mDataOutputBuffer.data(), mDataLength);
+        EXPECT_TRUE(result) << "can't read from Filter MQ";
+
+        /*for (int i = 0; i < mDataLength; i++) {
+            EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
+        }*/
+    }
+    mFilterIdToMQEventFlag[filterId]->wake(
+            static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+    return result;
+}
+
 // Test environment for Tuner HIDL HAL.
 class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
   public:
@@ -528,6 +497,7 @@
     sp<DemuxCallback> mDemuxCallback;
     MQDesc mFilterMQDescriptor;
     MQDesc mInputMQDescriptor;
+    vector<uint32_t> mUsedFilterIds;
 
     uint32_t mDemuxId;
     uint32_t mFilterId;
@@ -540,7 +510,8 @@
     ::testing::AssertionResult stopTuneFrontend(int32_t frontendId);
     ::testing::AssertionResult closeFrontend(int32_t frontendId);
     ::testing::AssertionResult createDemux();
-    ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId);
+    ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId,
+                                                       FrontendSettings settings);
     ::testing::AssertionResult getInputMQDescriptor();
     ::testing::AssertionResult addInputToDemux(DemuxInputSettings setting);
     ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting);
@@ -552,10 +523,8 @@
     ::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
                                                     InputConf inputConf,
                                                     vector<string> goldenOutputFiles);
-
-    // Legacy
-    ::testing::AssertionResult addSectionFilterToDemux();
-    ::testing::AssertionResult readSectionFilterDataOutput();
+    ::testing::AssertionResult broadcastDataFlowTest(vector<FilterConf> filterConf,
+                                                     vector<string> goldenOutputFiles);
 };
 
 ::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) {
@@ -586,7 +555,7 @@
             .frequency = 0,
             .modulation = FrontendAtscModulation::UNDEFINED,
     };
-    frontendSettings.atsc() = frontendAtscSettings;
+    frontendSettings.atsc(frontendAtscSettings);
     mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
 
     FrontendDvbtSettings frontendDvbtSettings{
@@ -630,7 +599,8 @@
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
-::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId) {
+::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId,
+                                                                  FrontendSettings settings) {
     Result status;
 
     if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
@@ -641,6 +611,8 @@
         return ::testing::AssertionFailure();
     }
 
+    mFrontendCallback->testOnEvent(mFrontend, settings);
+
     status = mDemux->setFrontendDataSource(frontendId);
 
     return ::testing::AssertionResult(status == Result::SUCCESS);
@@ -705,7 +677,7 @@
         mDemuxCallback = new DemuxCallback();
     }
 
-    // Add section filter to the local demux
+    // Add playback input to the local demux
     status = mDemux->addInput(FMQ_SIZE_1M, mDemuxCallback);
 
     if (status != Result::SUCCESS) {
@@ -732,29 +704,6 @@
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
-// Legacy
-::testing::AssertionResult TunerHidlTest::addSectionFilterToDemux() {
-    Result status;
-
-    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Create demux callback
-    if (!mDemuxCallback) {
-        mDemuxCallback = new DemuxCallback();
-    }
-
-    // Add section filter to the local demux
-    mDemux->addFilter(DemuxFilterType::SECTION, FMQ_SIZE_4K, mDemuxCallback,
-                      [&](Result result, uint32_t filterId) {
-                          mFilterId = filterId;
-                          status = result;
-                      });
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
 ::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type,
                                                            DemuxFilterSettings setting) {
     Result status;
@@ -800,36 +749,10 @@
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
-// Legacy
-::testing::AssertionResult TunerHidlTest::readSectionFilterDataOutput() {
-    // Filter Configuration Module
-    DemuxInputSettings setting{
-            .statusMask = 0xf,
-            .lowThreshold = 0x1000,
-            .highThreshold = 0x100000,
-            .dataFormat = DemuxDataFormat::TS,
-            .packetSize = 188,
-    };
-    if (addSectionFilterToDemux() == ::testing::AssertionFailure() ||
-        getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure() ||
-        addInputToDemux(setting) == ::testing::AssertionFailure() ||
-        getInputMQDescriptor() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Data Verify Module
-    // Test start filter and read the output data
-    mDemuxCallback->testOnSectionFilterEvent(mDemux, mFilterId, mFilterMQDescriptor,
-                                             mInputMQDescriptor);
-
-    // Clean Up Module
-    return closeDemux();  //::testing::AssertionSuccess();
-}
-
-::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(vector<FilterConf> filterConf,
-                                                               InputConf inputConf,
-                                                               vector<string> goldenOutputFiles) {
+::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(
+        vector<FilterConf> filterConf, InputConf inputConf, vector<string> /*goldenOutputFiles*/) {
     Result status;
+    int filterIdsSize;
     // Filter Configuration Module
     for (int i = 0; i < filterConf.size(); i++) {
         if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
@@ -838,8 +761,11 @@
             getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) {
             return ::testing::AssertionFailure();
         }
+        filterIdsSize = mUsedFilterIds.size();
+        mUsedFilterIds.resize(filterIdsSize + 1);
+        mUsedFilterIds[filterIdsSize] = mFilterId;
         mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor);
-        mDemuxCallback->updateGoldenOutputMap(mFilterId, goldenOutputFiles[i]);
+        // mDemuxCallback->updateGoldenOutputMap(mFilterId, goldenOutputFiles[i]);
         status = mDemux->startFilter(mFilterId);
         if (status != Result::SUCCESS) {
             return ::testing::AssertionFailure();
@@ -860,8 +786,76 @@
 
     // Data Verify Module
     mDemuxCallback->testFilterDataOutput();
+    mDemuxCallback->stopInputThread();
 
     // Clean Up Module
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+    if (mDemux->stopInput() != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+    return closeDemux();
+}
+
+::testing::AssertionResult TunerHidlTest::broadcastDataFlowTest(
+        vector<FilterConf> filterConf, vector<string> /*goldenOutputFiles*/) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return ::testing::AssertionFailure();
+    }
+
+    FrontendDvbtSettings dvbt{
+            .frequency = 1000,
+    };
+    FrontendSettings settings;
+    settings.dvbt(dvbt);
+
+    if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) {
+        return ::testing::AssertionFailure();
+    }
+
+    int filterIdsSize;
+    // Filter Configuration Module
+    for (int i = 0; i < filterConf.size(); i++) {
+        if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
+                    ::testing::AssertionFailure() ||
+            // TODO use a map to save the FMQs/EvenFlags and pass to callback
+            getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) {
+            return ::testing::AssertionFailure();
+        }
+        filterIdsSize = mUsedFilterIds.size();
+        mUsedFilterIds.resize(filterIdsSize + 1);
+        mUsedFilterIds[filterIdsSize] = mFilterId;
+        mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor);
+        status = mDemux->startFilter(mFilterId);
+        if (status != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+
+    // Data Verify Module
+    mDemuxCallback->testFilterDataOutput();
+
+    // Clean Up Module
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+    if (mFrontend->stopTune() != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
     return closeDemux();
 }
 
@@ -948,7 +942,7 @@
     }
 }
 
-TEST_F(TunerHidlTest, CreateDemuxWithFrontend) {
+/*TEST_F(TunerHidlTest, CreateDemuxWithFrontend) {
     Result status;
     hidl_vec<FrontendId> feIds;
 
@@ -963,10 +957,17 @@
         return;
     }
 
+    FrontendDvbtSettings dvbt{
+        .frequency = 1000,
+    };
+    FrontendSettings settings;
+    settings.dvbt(dvbt);
+
     for (size_t i = 0; i < feIds.size(); i++) {
-        ASSERT_TRUE(createDemuxWithFrontend(feIds[i]));
+        ASSERT_TRUE(createDemuxWithFrontend(feIds[i], settings));
+        mFrontend->stopTune();
     }
-}
+}*/
 
 TEST_F(TunerHidlTest, CreateDemux) {
     description("Create Demux");
@@ -991,9 +992,63 @@
 /*
  * DATA FLOW TESTS
  */
-TEST_F(TunerHidlTest, ReadSectionFilterOutput) {
-    description("Read data output from FMQ of a Section Filter");
-    ASSERT_TRUE(readSectionFilterDataOutput());
+TEST_F(TunerHidlTest, PlaybackDataFlowWithPesFilterTest) {
+    description("Feed ts data from playback and configure pes filter to get output");
+
+    // todo modulize the filter conf parser
+    vector<FilterConf> filterConf;
+    filterConf.resize(1);
+
+    DemuxFilterSettings filterSetting;
+    DemuxFilterPesDataSettings pesFilterSetting{
+            .tpid = 18,
+    };
+    filterSetting.pesData(pesFilterSetting);
+    FilterConf pesFilterConf{
+            .type = DemuxFilterType::PES,
+            .setting = filterSetting,
+    };
+    filterConf[0] = pesFilterConf;
+
+    DemuxInputSettings inputSetting{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x07fff,
+            .dataFormat = DemuxDataFormat::TS,
+            .packetSize = 188,
+    };
+
+    InputConf inputConf{
+            .inputDataFile = "/vendor/etc/test1.ts",
+            .setting = inputSetting,
+    };
+
+    vector<string> goldenOutputFiles;
+
+    ASSERT_TRUE(playbackDataFlowTest(filterConf, inputConf, goldenOutputFiles));
+}
+
+TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) {
+    description("Feed ts data from frontend and test with PES filter");
+
+    // todo modulize the filter conf parser
+    vector<FilterConf> filterConf;
+    filterConf.resize(1);
+
+    DemuxFilterSettings filterSetting;
+    DemuxFilterPesDataSettings pesFilterSetting{
+            .tpid = 18,
+    };
+    filterSetting.pesData(pesFilterSetting);
+    FilterConf pesFilterConf{
+            .type = DemuxFilterType::PES,
+            .setting = filterSetting,
+    };
+    filterConf[0] = pesFilterConf;
+
+    vector<string> goldenOutputFiles;
+
+    ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles));
 }
 
 }  // namespace
diff --git a/tv/tuner/README.md b/tv/tuner/README.md
new file mode 100644
index 0000000..a833c87
--- /dev/null
+++ b/tv/tuner/README.md
@@ -0,0 +1,12 @@
+# Tuner HALs
+
+## Overview
+
+TV specific tuners.
+
+Sett 1.0/ITuner.hal for an overview.
+
+*** note
+**Warning:** The HALs are not (yet) frozen, as the HAL definition is
+expected to evolve between Android releases.
+***
diff --git a/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp b/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp
index b51cc96..1b6abe9 100644
--- a/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp
+++ b/vibrator/1.4/vts/functional/VtsHalVibratorV1_4TargetTest.cpp
@@ -22,6 +22,8 @@
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
+
+#include <getopt.h>
 #include <unistd.h>
 
 #include <future>
@@ -38,6 +40,8 @@
 using ::android::hardware::vibrator::V1_4::IVibrator;
 using ::android::hardware::vibrator::V1_4::IVibratorCallback;
 
+static uint32_t sCompletionLimitMs = UINT32_MAX;
+
 #define EXPECT_OK(ret) ASSERT_TRUE((ret).isOk())
 
 class CompletionCallback : public IVibratorCallback {
@@ -115,7 +119,7 @@
             sp<CompletionCallback> callback =
                     new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
             EXPECT_OK(vibrator->perform_1_4(effect, strength, callback, validateWrapper));
-            if (performStatus == Status::OK &&
+            if (performStatus == Status::OK && performLength < sCompletionLimitMs &&
                 (capabilities & Capabilities::PERFORM_COMPLETION_CALLBACK)) {
                 std::chrono::milliseconds timeout{performLength * 2};
                 EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
@@ -168,3 +172,32 @@
         PerInstance, VibratorHidlTest_1_4,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVibrator::descriptor)),
         android::hardware::PrintInstanceNameToString);
+
+enum {
+    OPTION_COMPLETION_LIMIT_MS,
+};
+
+int main(int argc, char** argv) {
+    struct option options[] = {
+            {"completion-limit-ms", required_argument, 0, OPTION_COMPLETION_LIMIT_MS}, {}};
+
+    printf("Running main() from %s\n", __FILE__);
+    testing::InitGoogleTest(&argc, argv);
+
+    while (true) {
+        int opt = getopt_long(argc, argv, "", options, nullptr);
+        if (opt == -1) {
+            break;
+        }
+        switch (opt) {
+            case OPTION_COMPLETION_LIMIT_MS:
+                std::istringstream(optarg) >> sCompletionLimitMs;
+                break;
+            default:
+                printf("Unrecognized option\n");
+                return -EINVAL;
+        }
+    }
+
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 397ad17..6fa6e7e 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -28,7 +28,9 @@
     shared_libs: [
         "libnativehelper",
     ],
-    static_libs: ["android.hardware.wifi@1.0"],
+    static_libs: [
+        "android.hardware.wifi@1.0",
+    ],
 }
 
 cc_test {
@@ -36,7 +38,6 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "VtsHalWifiV1_0TargetTest.cpp",
-        "wifi_ap_iface_hidl_test.cpp",
         "wifi_chip_hidl_test.cpp",
         "wifi_p2p_iface_hidl_test.cpp",
         "wifi_rtt_controller_hidl_test.cpp",
@@ -52,11 +53,14 @@
     test_suites: ["general-tests"],
 }
 
+// These tests are split out so that they can be conditioned on presence of the
+// "android.hardware.wifi.aware" feature.
 cc_test {
     name: "VtsHalWifiNanV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "VtsHalWifiV1_0TargetTest.cpp",
+        "wifi_chip_hidl_nan_test.cpp",
         "wifi_nan_iface_hidl_test.cpp",
     ],
     static_libs: [
@@ -65,3 +69,20 @@
     ],
     test_suites: ["general-tests"],
 }
+
+// These tests are split out so that they can be conditioned on presence of
+// the hostapd HAL, which indicates SoftAP support.
+cc_test {
+    name: "VtsHalWifiApV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalWifiV1_0TargetTest.cpp",
+        "wifi_ap_iface_hidl_test.cpp",
+        "wifi_chip_hidl_ap_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
index e7b8593..9d25014 100644
--- a/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
+++ b/wifi/1.0/vts/functional/VtsHalWifiV1_0TargetTest.cpp
@@ -41,10 +41,7 @@
     ::testing::AddGlobalTestEnvironment(gEnv);
     ::testing::InitGoogleTest(&argc, argv);
     gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        status = RUN_ALL_TESTS();
-        LOG(INFO) << "Test result = " << status;
-    }
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
     return status;
 }
diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
index e5762f2..c55221d 100644
--- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -29,21 +29,17 @@
 using ::android::hardware::wifi::V1_0::WifiStatusCode;
 using ::android::sp;
 
-extern WifiHidlEnvironment* gEnv;
-
 /**
  * Fixture to use for all AP Iface HIDL interface tests.
  */
 class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    public:
     virtual void SetUp() override {
-        if (!gEnv->isSoftApOn) return;
         wifi_ap_iface_ = getWifiApIface();
         ASSERT_NE(nullptr, wifi_ap_iface_.get());
     }
 
     virtual void TearDown() override {
-        if (!gEnv->isSoftApOn) return;
         stopWifi();
     }
 
@@ -57,7 +53,6 @@
  * successfully created.
  */
 TEST(WifiApIfaceHidlTestNoFixture, Create) {
-    if (!gEnv->isSoftApOn) return;
     EXPECT_NE(nullptr, getWifiApIface().get());
     stopWifi();
 }
@@ -67,7 +62,6 @@
  * Ensures that the correct interface type is returned for AP interface.
  */
 TEST_F(WifiApIfaceHidlTest, GetType) {
-    if (!gEnv->isSoftApOn) return;
     const auto& status_and_type = HIDL_INVOKE(wifi_ap_iface_, getType);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_type.first.code);
     EXPECT_EQ(IfaceType::AP, status_and_type.second);
@@ -79,7 +73,6 @@
  * status code.
  */
 TEST_F(WifiApIfaceHidlTest, SetCountryCode) {
-    if (!gEnv->isSoftApOn) return;
     const android::hardware::hidl_array<int8_t, 2> kCountryCode{
         std::array<int8_t, 2>{{0x55, 0x53}}};
     EXPECT_EQ(WifiStatusCode::SUCCESS,
@@ -91,7 +84,6 @@
  * Ensures that we can retrieve valid frequencies for 2.4 GHz band.
  */
 TEST_F(WifiApIfaceHidlTest, GetValidFrequenciesForBand) {
-    if (!gEnv->isSoftApOn) return;
     const auto& status_and_freqs = HIDL_INVOKE(
         wifi_ap_iface_, getValidFrequenciesForBand, WifiBand::BAND_24GHZ);
     EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_freqs.first.code);
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
new file mode 100644
index 0000000..232ffdd
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/wifi/1.0/IWifiChip.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifiApIface;
+using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::V1_0::IWifiIface;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+
+/**
+ * Fixture for IWifiChip tests that are conditioned on SoftAP support.
+ */
+class WifiChipHidlApTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        wifi_chip_ = getWifiChip();
+        ASSERT_NE(nullptr, wifi_chip_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(); }
+
+   protected:
+    // Helper function to configure the Chip in one of the supported modes.
+    // Most of the non-mode-configuration-related methods require chip
+    // to be first configured.
+    ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) {
+        ChipModeId mode_id;
+        EXPECT_EQ(expectSuccess,
+                  configureChipToSupportIfaceType(wifi_chip_, type, &mode_id));
+        return mode_id;
+    }
+
+    std::string getIfaceName(const sp<IWifiIface>& iface) {
+        const auto& status_and_name = HIDL_INVOKE(iface, getName);
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_name.first.code);
+        return status_and_name.second;
+    }
+
+    WifiStatusCode createApIface(sp<IWifiApIface>* ap_iface) {
+        const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createApIface);
+        *ap_iface = status_and_iface.second;
+        return status_and_iface.first.code;
+    }
+
+    WifiStatusCode removeApIface(const std::string& name) {
+        return HIDL_INVOKE(wifi_chip_, removeApIface, name).code;
+    }
+
+    sp<IWifiChip> wifi_chip_;
+};
+
+/*
+ * CreateApIface
+ * Configures the chip in AP mode and ensures that at least 1 iface creation
+ * succeeds.
+ */
+TEST_F(WifiChipHidlApTest, CreateApIface) {
+    configureChipForIfaceType(IfaceType::AP, true);
+
+    sp<IWifiApIface> iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
+    EXPECT_NE(nullptr, iface.get());
+}
+
+/*
+ * GetApIfaceNames
+ * Configures the chip in AP mode and ensures that the iface list is empty
+ * before creating the iface. Then, create the iface and ensure that
+ * iface name is returned via the list.
+ */
+TEST_F(WifiChipHidlApTest, GetApIfaceNames) {
+    configureChipForIfaceType(IfaceType::AP, true);
+
+    const auto& status_and_iface_names1 =
+        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
+    EXPECT_EQ(0u, status_and_iface_names1.second.size());
+
+    sp<IWifiApIface> iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
+    EXPECT_NE(nullptr, iface.get());
+
+    std::string iface_name = getIfaceName(iface);
+    const auto& status_and_iface_names2 =
+        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
+    EXPECT_EQ(1u, status_and_iface_names2.second.size());
+    EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
+
+    EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
+    const auto& status_and_iface_names3 =
+        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
+    EXPECT_EQ(0u, status_and_iface_names3.second.size());
+}
+
+/*
+ * GetApIface
+ * Configures the chip in AP mode and create an iface. Then, retrieve
+ * the iface object using the correct name and ensure any other name
+ * doesn't retrieve an iface object.
+ */
+TEST_F(WifiChipHidlApTest, GetApIface) {
+    configureChipForIfaceType(IfaceType::AP, true);
+
+    sp<IWifiApIface> ap_iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
+    EXPECT_NE(nullptr, ap_iface.get());
+
+    std::string iface_name = getIfaceName(ap_iface);
+    const auto& status_and_iface1 =
+        HIDL_INVOKE(wifi_chip_, getApIface, iface_name);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
+    EXPECT_NE(nullptr, status_and_iface1.second.get());
+
+    std::string invalid_name = iface_name + "0";
+    const auto& status_and_iface2 =
+        HIDL_INVOKE(wifi_chip_, getApIface, invalid_name);
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
+    EXPECT_EQ(nullptr, status_and_iface2.second.get());
+}
+
+/*
+ * RemoveApIface
+ * Configures the chip in AP mode and create an iface. Then, remove
+ * the iface object using the correct name and ensure any other name
+ * doesn't remove the iface.
+ */
+TEST_F(WifiChipHidlApTest, RemoveApIface) {
+    configureChipForIfaceType(IfaceType::AP, true);
+
+    sp<IWifiApIface> ap_iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
+    EXPECT_NE(nullptr, ap_iface.get());
+
+    std::string iface_name = getIfaceName(ap_iface);
+    std::string invalid_name = iface_name + "0";
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(invalid_name));
+    EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
+
+    // No such iface exists now. So, this should return failure.
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name));
+}
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
new file mode 100644
index 0000000..595f23a
--- /dev/null
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_nan_test.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/wifi/1.0/IWifiChip.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::IWifiChip;
+using ::android::hardware::wifi::V1_0::IWifiIface;
+using ::android::hardware::wifi::V1_0::IWifiNanIface;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+
+/**
+ * Fixture for IWifiChip tests that are conditioned on NAN support.
+ */
+class WifiChipHidlNanTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        wifi_chip_ = getWifiChip();
+        ASSERT_NE(nullptr, wifi_chip_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(); }
+
+   protected:
+    // Helper function to configure the Chip in one of the supported modes.
+    // Most of the non-mode-configuration-related methods require chip
+    // to be first configured.
+    ChipModeId configureChipForIfaceType(IfaceType type, bool expectSuccess) {
+        ChipModeId mode_id;
+        EXPECT_EQ(expectSuccess,
+                  configureChipToSupportIfaceType(wifi_chip_, type, &mode_id));
+        return mode_id;
+    }
+
+    std::string getIfaceName(const sp<IWifiIface>& iface) {
+        const auto& status_and_name = HIDL_INVOKE(iface, getName);
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_name.first.code);
+        return status_and_name.second;
+    }
+
+    WifiStatusCode createNanIface(sp<IWifiNanIface>* nan_iface) {
+        const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createNanIface);
+        *nan_iface = status_and_iface.second;
+        return status_and_iface.first.code;
+    }
+
+    WifiStatusCode removeNanIface(const std::string& name) {
+        return HIDL_INVOKE(wifi_chip_, removeNanIface, name).code;
+    }
+
+    sp<IWifiChip> wifi_chip_;
+};
+
+/*
+ * CreateNanIface
+ * Configures the chip in NAN mode and ensures that at least 1 iface creation
+ * succeeds.
+ */
+TEST_F(WifiChipHidlNanTest, CreateNanIface) {
+    configureChipForIfaceType(IfaceType::NAN, true);
+
+    sp<IWifiNanIface> iface;
+    ASSERT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
+    EXPECT_NE(nullptr, iface.get());
+}
+
+/*
+ * GetNanIfaceNames
+ * Configures the chip in NAN mode and ensures that the iface list is empty
+ * before creating the iface. Then, create the iface and ensure that
+ * iface name is returned via the list.
+ */
+TEST_F(WifiChipHidlNanTest, GetNanIfaceNames) {
+    configureChipForIfaceType(IfaceType::NAN, true);
+
+    const auto& status_and_iface_names1 =
+        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
+    ASSERT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
+    EXPECT_EQ(0u, status_and_iface_names1.second.size());
+
+    sp<IWifiNanIface> iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
+    EXPECT_NE(nullptr, iface.get());
+
+    std::string iface_name = getIfaceName(iface);
+    const auto& status_and_iface_names2 =
+        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
+    EXPECT_EQ(1u, status_and_iface_names2.second.size());
+    EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
+
+    EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
+    const auto& status_and_iface_names3 =
+        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
+    EXPECT_EQ(0u, status_and_iface_names3.second.size());
+}
+
+/*
+ * GetNanIface
+ * Configures the chip in NAN mode and create an iface. Then, retrieve
+ * the iface object using the correct name and ensure any other name
+ * doesn't retrieve an iface object.
+ */
+TEST_F(WifiChipHidlNanTest, GetNanIface) {
+    configureChipForIfaceType(IfaceType::NAN, true);
+
+    sp<IWifiNanIface> nan_iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
+    EXPECT_NE(nullptr, nan_iface.get());
+
+    std::string iface_name = getIfaceName(nan_iface);
+    const auto& status_and_iface1 =
+        HIDL_INVOKE(wifi_chip_, getNanIface, iface_name);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
+    EXPECT_NE(nullptr, status_and_iface1.second.get());
+
+    std::string invalid_name = iface_name + "0";
+    const auto& status_and_iface2 =
+        HIDL_INVOKE(wifi_chip_, getNanIface, invalid_name);
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
+    EXPECT_EQ(nullptr, status_and_iface2.second.get());
+}
+
+/*
+ * RemoveNanIface
+ * Configures the chip in NAN mode and create an iface. Then, remove
+ * the iface object using the correct name and ensure any other name
+ * doesn't remove the iface.
+ */
+TEST_F(WifiChipHidlNanTest, RemoveNanIface) {
+    configureChipForIfaceType(IfaceType::NAN, true);
+
+    sp<IWifiNanIface> nan_iface;
+    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
+    EXPECT_NE(nullptr, nan_iface.get());
+
+    std::string iface_name = getIfaceName(nan_iface);
+    std::string invalid_name = iface_name + "0";
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(invalid_name));
+
+    EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
+
+    // No such iface exists now. So, this should return failure.
+    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name));
+}
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
index 1b7e821..2601b78 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_test.cpp
@@ -36,9 +36,7 @@
 using ::android::hardware::wifi::V1_0::WifiStatus;
 using ::android::hardware::wifi::V1_0::WifiStatusCode;
 using ::android::hardware::wifi::V1_0::IWifiChip;
-using ::android::hardware::wifi::V1_0::IWifiApIface;
 using ::android::hardware::wifi::V1_0::IWifiIface;
-using ::android::hardware::wifi::V1_0::IWifiNanIface;
 using ::android::hardware::wifi::V1_0::IWifiP2pIface;
 using ::android::hardware::wifi::V1_0::IWifiRttController;
 using ::android::hardware::wifi::V1_0::IWifiStaIface;
@@ -64,7 +62,10 @@
 }  // namespace
 
 /**
- * Fixture to use for all Wifi chip HIDL interface tests.
+ * Fixture for IWifiChip tests.
+ *
+ * Tests that require SoftAP or NAN support should go into WifiChipHidlApTest or
+ * WifiChipHidlNanTest respectively.
  */
 class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    public:
@@ -114,26 +115,6 @@
         return status_and_name.second;
     }
 
-    WifiStatusCode createApIface(sp<IWifiApIface>* ap_iface) {
-        const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createApIface);
-        *ap_iface = status_and_iface.second;
-        return status_and_iface.first.code;
-    }
-
-    WifiStatusCode removeApIface(const std::string& name) {
-        return HIDL_INVOKE(wifi_chip_, removeApIface, name).code;
-    }
-
-    WifiStatusCode createNanIface(sp<IWifiNanIface>* nan_iface) {
-        const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createNanIface);
-        *nan_iface = status_and_iface.second;
-        return status_and_iface.first.code;
-    }
-
-    WifiStatusCode removeNanIface(const std::string& name) {
-        return HIDL_INVOKE(wifi_chip_, removeNanIface, name).code;
-    }
-
     WifiStatusCode createP2pIface(sp<IWifiP2pIface>* p2p_iface) {
         const auto& status_and_iface = HIDL_INVOKE(wifi_chip_, createP2pIface);
         *p2p_iface = status_and_iface.second;
@@ -360,201 +341,6 @@
 }
 
 /*
- * CreateApIface
- * Configures the chip in AP mode and ensures that at least 1 iface creation
- * succeeds.
- */
-TEST_F(WifiChipHidlTest, CreateApIface) {
-    if (!gEnv->isSoftApOn) return;
-    configureChipForIfaceType(IfaceType::AP, true);
-
-    sp<IWifiApIface> iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
-}
-
-/*
- * GetApIfaceNames
- * Configures the chip in AP mode and ensures that the iface list is empty
- * before creating the iface. Then, create the iface and ensure that
- * iface name is returned via the list.
- */
-TEST_F(WifiChipHidlTest, GetApIfaceNames) {
-    if (!gEnv->isSoftApOn) return;
-    configureChipForIfaceType(IfaceType::AP, true);
-
-    const auto& status_and_iface_names1 =
-        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
-    EXPECT_EQ(0u, status_and_iface_names1.second.size());
-
-    sp<IWifiApIface> iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
-
-    std::string iface_name = getIfaceName(iface);
-    const auto& status_and_iface_names2 =
-        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
-    EXPECT_EQ(1u, status_and_iface_names2.second.size());
-    EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
-
-    EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
-    const auto& status_and_iface_names3 =
-        HIDL_INVOKE(wifi_chip_, getApIfaceNames);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
-    EXPECT_EQ(0u, status_and_iface_names3.second.size());
-}
-
-/*
- * GetApIface
- * Configures the chip in AP mode and create an iface. Then, retrieve
- * the iface object using the correct name and ensure any other name
- * doesn't retrieve an iface object.
- */
-TEST_F(WifiChipHidlTest, GetApIface) {
-    if (!gEnv->isSoftApOn) return;
-    configureChipForIfaceType(IfaceType::AP, true);
-
-    sp<IWifiApIface> ap_iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
-    EXPECT_NE(nullptr, ap_iface.get());
-
-    std::string iface_name = getIfaceName(ap_iface);
-    const auto& status_and_iface1 =
-        HIDL_INVOKE(wifi_chip_, getApIface, iface_name);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
-    EXPECT_NE(nullptr, status_and_iface1.second.get());
-
-    std::string invalid_name = iface_name + "0";
-    const auto& status_and_iface2 =
-        HIDL_INVOKE(wifi_chip_, getApIface, invalid_name);
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
-    EXPECT_EQ(nullptr, status_and_iface2.second.get());
-}
-
-/*
- * RemoveApIface
- * Configures the chip in AP mode and create an iface. Then, remove
- * the iface object using the correct name and ensure any other name
- * doesn't remove the iface.
- */
-TEST_F(WifiChipHidlTest, RemoveApIface) {
-    if (!gEnv->isSoftApOn) return;
-    configureChipForIfaceType(IfaceType::AP, true);
-
-    sp<IWifiApIface> ap_iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createApIface(&ap_iface));
-    EXPECT_NE(nullptr, ap_iface.get());
-
-    std::string iface_name = getIfaceName(ap_iface);
-    std::string invalid_name = iface_name + "0";
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(invalid_name));
-    EXPECT_EQ(WifiStatusCode::SUCCESS, removeApIface(iface_name));
-
-    // No such iface exists now. So, this should return failure.
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeApIface(iface_name));
-}
-
-/*
- * CreateNanIface
- * Configures the chip in NAN mode and ensures that at least 1 iface creation
- * succeeds.
- */
-TEST_F(WifiChipHidlTest, CreateNanIface) {
-    if (!gEnv->isNanOn) return;
-    configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
-    sp<IWifiNanIface> iface;
-    ASSERT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
-}
-
-/*
- * GetNanIfaceNames
- * Configures the chip in NAN mode and ensures that the iface list is empty
- * before creating the iface. Then, create the iface and ensure that
- * iface name is returned via the list.
- */
-TEST_F(WifiChipHidlTest, GetNanIfaceNames) {
-    if (!gEnv->isNanOn) return;
-    configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
-    const auto& status_and_iface_names1 =
-        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
-    ASSERT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names1.first.code);
-    EXPECT_EQ(0u, status_and_iface_names1.second.size());
-
-    sp<IWifiNanIface> iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&iface));
-    EXPECT_NE(nullptr, iface.get());
-
-    std::string iface_name = getIfaceName(iface);
-    const auto& status_and_iface_names2 =
-        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names2.first.code);
-    EXPECT_EQ(1u, status_and_iface_names2.second.size());
-    EXPECT_EQ(iface_name, status_and_iface_names2.second[0]);
-
-    EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
-    const auto& status_and_iface_names3 =
-        HIDL_INVOKE(wifi_chip_, getNanIfaceNames);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface_names3.first.code);
-    EXPECT_EQ(0u, status_and_iface_names3.second.size());
-}
-
-/*
- * GetNanIface
- * Configures the chip in NAN mode and create an iface. Then, retrieve
- * the iface object using the correct name and ensure any other name
- * doesn't retrieve an iface object.
- */
-TEST_F(WifiChipHidlTest, GetNanIface) {
-    if (!gEnv->isNanOn) return;
-    configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
-    sp<IWifiNanIface> nan_iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
-    EXPECT_NE(nullptr, nan_iface.get());
-
-    std::string iface_name = getIfaceName(nan_iface);
-    const auto& status_and_iface1 =
-        HIDL_INVOKE(wifi_chip_, getNanIface, iface_name);
-    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_iface1.first.code);
-    EXPECT_NE(nullptr, status_and_iface1.second.get());
-
-    std::string invalid_name = iface_name + "0";
-    const auto& status_and_iface2 =
-        HIDL_INVOKE(wifi_chip_, getNanIface, invalid_name);
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, status_and_iface2.first.code);
-    EXPECT_EQ(nullptr, status_and_iface2.second.get());
-}
-
-/*
- * RemoveNanIface
- * Configures the chip in NAN mode and create an iface. Then, remove
- * the iface object using the correct name and ensure any other name
- * doesn't remove the iface.
- */
-TEST_F(WifiChipHidlTest, RemoveNanIface) {
-    if (!gEnv->isNanOn) return;
-    configureChipForIfaceType(IfaceType::NAN, gEnv->isNanOn);
-
-    sp<IWifiNanIface> nan_iface;
-    EXPECT_EQ(WifiStatusCode::SUCCESS, createNanIface(&nan_iface));
-    EXPECT_NE(nullptr, nan_iface.get());
-
-    std::string iface_name = getIfaceName(nan_iface);
-    std::string invalid_name = iface_name + "0";
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(invalid_name));
-
-    EXPECT_EQ(WifiStatusCode::SUCCESS, removeNanIface(iface_name));
-
-    // No such iface exists now. So, this should return failure.
-    EXPECT_EQ(WifiStatusCode::ERROR_INVALID_ARGS, removeNanIface(iface_name));
-}
-
-/*
  * CreateP2pIface
  * Configures the chip in P2P mode and ensures that at least 1 iface creation
  * succeeds.
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
index d430ce0..7dacaf1 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.h
@@ -54,48 +54,4 @@
         stopWifi();
         sleep(5);
     }
-
-   public:
-    // Whether NaN feature is supported on the device.
-    bool isNanOn = false;
-    // Whether SoftAp feature is supported on the device.
-    bool isSoftApOn = false;
-
-    void usage(char* me, char* arg) {
-        fprintf(stderr,
-                "unrecognized option: %s\n\n"
-                "usage: %s <gtest options> <test options>\n\n"
-                "test options are:\n\n"
-                "-N, --nan_on: Whether NAN feature is supported\n"
-                "-S, --softap_on: Whether SOFTAP feature is supported\n",
-                arg, me);
-    }
-
-    int initFromOptions(int argc, char** argv) {
-        static struct option options[] = {{"nan_on", no_argument, 0, 'N'},
-                                          {"softap_on", no_argument, 0, 'S'},
-                                          {0, 0, 0, 0}};
-
-        int c;
-        while ((c = getopt_long(argc, argv, "NS", options, NULL)) >= 0) {
-            switch (c) {
-                case 'N':
-                    isNanOn = true;
-                    break;
-                case 'S':
-                    isSoftApOn = true;
-                    break;
-                default:
-                    usage(argv[0], argv[optind]);
-                    return 2;
-            }
-        }
-
-        if (optind < argc) {
-            usage(argv[0], argv[optind]);
-            return 2;
-        }
-
-        return 0;
-    }
 };
diff --git a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
index a0f97f8..673fed3 100644
--- a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
+++ b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
@@ -41,10 +41,7 @@
     ::testing::AddGlobalTestEnvironment(gEnv);
     ::testing::InitGoogleTest(&argc, argv);
     gEnv->init(&argc, argv);
-    int status = gEnv->initFromOptions(argc, argv);
-    if (status == 0) {
-        int status = RUN_ALL_TESTS();
-        LOG(INFO) << "Test result = " << status;
-    }
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
     return status;
 }
diff --git a/wifi/1.4/Android.bp b/wifi/1.4/Android.bp
index a6ac020..aba8b44 100644
--- a/wifi/1.4/Android.bp
+++ b/wifi/1.4/Android.bp
@@ -8,6 +8,7 @@
     },
     srcs: [
         "IWifi.hal",
+        "IWifiApIface.hal",
     ],
     interfaces: [
         "android.hardware.wifi@1.0",
diff --git a/wifi/1.4/IWifiApIface.hal b/wifi/1.4/IWifiApIface.hal
new file mode 100644
index 0000000..af88afb
--- /dev/null
+++ b/wifi/1.4/IWifiApIface.hal
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.4;
+
+import @1.0::IWifiApIface;
+import @1.0::MacAddress;
+import @1.0::WifiStatus;
+
+/**
+ * Represents a network interface in AP mode.
+ *
+ * This can be obtained through @1.0::IWifiChip.getApIface() and casting
+ * IWifiApIface up to 1.4.
+ */
+interface IWifiApIface extends @1.0::IWifiApIface {
+    /**
+     * Changes the MAC address of the interface to the given MAC address.
+     *
+     * @param mac MAC address to change to.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    setMacAddress(MacAddress mac) generates (WifiStatus status);
+
+    /**
+     * Gets the factory MAC address of the interface.
+     *
+     * @return status WifiStatus of the operation
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     * @return mac factory MAC address of the interface
+     */
+     getFactoryMacAddress() generates (WifiStatus status, MacAddress mac);
+};
diff --git a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
index 2ad093a..b0357ba 100644
--- a/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.4/default/tests/wifi_chip_unit_tests.cpp
@@ -173,8 +173,9 @@
     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) {
+            chip_->createApIface([&iface_name](
+                                     const WifiStatus& status,
+                                     const sp<V1_0::IWifiApIface>& iface) {
                 if (WifiStatusCode::SUCCESS == status.code) {
                     ASSERT_NE(iface.get(), nullptr);
                     iface->getName([&iface_name](const WifiStatus& status,
diff --git a/wifi/1.4/default/wifi_ap_iface.cpp b/wifi/1.4/default/wifi_ap_iface.cpp
index 13ce2dd..b860910 100644
--- a/wifi/1.4/default/wifi_ap_iface.cpp
+++ b/wifi/1.4/default/wifi_ap_iface.cpp
@@ -85,6 +85,20 @@
                            hidl_status_cb, band);
 }
 
+Return<void> WifiApIface::setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                                        setMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::setMacAddressInternal, hidl_status_cb,
+                           mac);
+}
+
+Return<void> WifiApIface::getFactoryMacAddress(
+    getFactoryMacAddress_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiApIface::getFactoryMacAddressInternal,
+                           hidl_status_cb);
+}
+
 std::pair<WifiStatus, std::string> WifiApIface::getNameInternal() {
     return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
 }
@@ -111,6 +125,26 @@
             ifname_, hidl_struct_util::convertHidlWifiBandToLegacy(band));
     return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
 }
+
+WifiStatus WifiApIface::setMacAddressInternal(
+    const std::array<uint8_t, 6>& mac) {
+    bool status = iface_util_.lock()->setMacAddress(ifname_, mac);
+    if (!status) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+std::pair<WifiStatus, std::array<uint8_t, 6>>
+WifiApIface::getFactoryMacAddressInternal() {
+    std::array<uint8_t, 6> mac =
+        iface_util_.lock()->getFactoryMacAddress(ifname_);
+    if (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 &&
+        mac[4] == 0 && mac[5] == 0) {
+        return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), mac};
+    }
+    return {createWifiStatus(WifiStatusCode::SUCCESS), mac};
+}
 }  // namespace implementation
 }  // namespace V1_4
 }  // namespace wifi
diff --git a/wifi/1.4/default/wifi_ap_iface.h b/wifi/1.4/default/wifi_ap_iface.h
index 179acac..cb3ed3d 100644
--- a/wifi/1.4/default/wifi_ap_iface.h
+++ b/wifi/1.4/default/wifi_ap_iface.h
@@ -18,7 +18,7 @@
 #define WIFI_AP_IFACE_H_
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiApIface.h>
+#include <android/hardware/wifi/1.4/IWifiApIface.h>
 
 #include "wifi_feature_flags.h"
 #include "wifi_iface_util.h"
@@ -34,7 +34,7 @@
 /**
  * HIDL interface object used to control a AP Iface instance.
  */
-class WifiApIface : public V1_0::IWifiApIface {
+class WifiApIface : public V1_4::IWifiApIface {
    public:
     WifiApIface(
         const std::string& ifname,
@@ -53,6 +53,10 @@
                                 setCountryCode_cb hidl_status_cb) override;
     Return<void> getValidFrequenciesForBand(
         WifiBand band, getValidFrequenciesForBand_cb hidl_status_cb) override;
+    Return<void> setMacAddress(const hidl_array<uint8_t, 6>& mac,
+                               setMacAddress_cb hidl_status_cb) override;
+    Return<void> getFactoryMacAddress(
+        getFactoryMacAddress_cb hidl_status_cb) override;
 
    private:
     // Corresponding worker functions for the HIDL methods.
@@ -61,6 +65,9 @@
     WifiStatus setCountryCodeInternal(const std::array<int8_t, 2>& code);
     std::pair<WifiStatus, std::vector<WifiChannelInMhz>>
     getValidFrequenciesForBandInternal(WifiBand band);
+    WifiStatus setMacAddressInternal(const std::array<uint8_t, 6>& mac);
+    std::pair<WifiStatus, std::array<uint8_t, 6>>
+    getFactoryMacAddressInternal();
 
     std::string ifname_;
     std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
diff --git a/wifi/1.4/vts/OWNERS b/wifi/1.4/vts/OWNERS
new file mode 100644
index 0000000..8bfb148
--- /dev/null
+++ b/wifi/1.4/vts/OWNERS
@@ -0,0 +1,2 @@
+rpius@google.com
+etancohen@google.com
diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp
new file mode 100644
index 0000000..42c60f2
--- /dev/null
+++ b/wifi/1.4/vts/functional/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest.
+cc_test {
+    name: "VtsHalWifiApV1_4TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalWifiV1_4TargetTest.cpp",
+        "wifi_ap_iface_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+    ],
+}
diff --git a/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp
new file mode 100644
index 0000000..deac0fa
--- /dev/null
+++ b/wifi/1.4/vts/functional/VtsHalWifiV1_4TargetTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/wifi/1.4/IWifi.h>
+
+#include "wifi_hidl_test_utils.h"
+
+using ::android::hardware::wifi::V1_4::IWifi;
+
+// Test environment for Wifi HIDL HAL.
+class WifiHidlEnvironment_1_4 : public WifiHidlEnvironment {
+   public:
+    // get the test environment singleton
+    static WifiHidlEnvironment_1_4* Instance() {
+        static WifiHidlEnvironment_1_4* instance = new WifiHidlEnvironment_1_4;
+        return instance;
+    }
+
+    virtual void registerTestServices() override {
+        registerTestService<android::hardware::wifi::V1_4::IWifi>();
+    }
+
+   private:
+    WifiHidlEnvironment_1_4() {}
+};
+
+WifiHidlEnvironment_1_4* gEnv = WifiHidlEnvironment_1_4::Instance();
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnv->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
new file mode 100644
index 0000000..68e9bbb
--- /dev/null
+++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Staache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/wifi/1.4/IWifiApIface.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_4::IWifiApIface;
+
+extern WifiHidlEnvironment* gEnv;
+
+/**
+ * Fixture to use for all STA Iface HIDL interface tests.
+ */
+class WifiApIfaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        wifi_ap_iface_ = IWifiApIface::castFrom(getWifiApIface());
+        ASSERT_NE(nullptr, wifi_ap_iface_.get());
+    }
+
+    virtual void TearDown() override {
+        stopWifi();
+    }
+
+   protected:
+    sp<IWifiApIface> wifi_ap_iface_;
+};
+
+/*
+ * SetMacAddress:
+ * Ensures that calls to set MAC address will return a success status
+ * code.
+ */
+TEST_F(WifiApIfaceHidlTest, SetMacAddress) {
+    const hidl_array<uint8_t, 6> kMac{{0x12, 0x22, 0x33, 0x52, 0x10, 0x41}};
+    EXPECT_EQ(WifiStatusCode::SUCCESS,
+              HIDL_INVOKE(wifi_ap_iface_, setMacAddress, kMac).code);
+}
+
+/*
+ * GetFactoryMacAddress:
+ * Ensures that calls to get factory MAC address will retrieve a non-zero MAC
+ * and return a success status code.
+ */
+TEST_F(WifiApIfaceHidlTest, GetFactoryMacAddress) {
+    std::pair<WifiStatus, hidl_array<uint8_t, 6> > status_and_mac =
+        HIDL_INVOKE(wifi_ap_iface_, getFactoryMacAddress);
+    EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_mac.first.code);
+    hidl_array<uint8_t, 6> all_zero{};
+    EXPECT_NE(all_zero, status_and_mac.second);
+}