Merge "move duplicate code to common"
diff --git a/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd b/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd
deleted file mode 100644
index 64647de..0000000
--- a/audio/effect/2.0/xml/audio_effects_conf_V2_0.xsd
+++ /dev/null
@@ -1,238 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
-           targetNamespace="http://schemas.android.com/audio/audio_effects_conf/v2_0"
-           xmlns:aec="http://schemas.android.com/audio/audio_effects_conf/v2_0"
-           elementFormDefault="qualified">
-
-  <!-- Simple types -->
-  <xs:simpleType name="versionType">
-    <xs:restriction base="xs:decimal">
-      <xs:enumeration value="2.0"/>
-    </xs:restriction>
-  </xs:simpleType>
-  <xs:simpleType name="uuidType">
-    <xs:restriction base="xs:string">
-      <xs:pattern value="[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}"/>
-    </xs:restriction>
-  </xs:simpleType>
-  <xs:simpleType name="streamInputType">
-    <xs:restriction base="xs:string">
-      <xs:enumeration value="mic"/>
-      <xs:enumeration value="voice_uplink"/>
-      <xs:enumeration value="voice_downlink"/>
-      <xs:enumeration value="voice_call"/>
-      <xs:enumeration value="camcorder"/>
-      <xs:enumeration value="voice_recognition"/>
-      <xs:enumeration value="voice_communication"/>
-      <xs:enumeration value="unprocessed"/>
-    </xs:restriction>
-  </xs:simpleType>
-  <xs:simpleType name="streamOutputType">
-    <xs:restriction base="xs:string">
-      <xs:enumeration value="default"/>
-      <xs:enumeration value="voice_call"/>
-      <xs:enumeration value="system"/>
-      <xs:enumeration value="ring"/>
-      <xs:enumeration value="music"/>
-      <xs:enumeration value="alarm"/>
-      <xs:enumeration value="notification"/>
-      <xs:enumeration value="bluetooth_sco"/>
-      <xs:enumeration value="enforced_audible"/>
-      <xs:enumeration value="dtmf"/>
-      <xs:enumeration value="tts"/>
-    </xs:restriction>
-  </xs:simpleType>
-
-  <!-- Complex types -->
-  <xs:complexType name="libraryType">
-    <xs:annotation>
-      <xs:documentation xml:lang="en">
-        List of effect libraries to load. Each library element must have "name" and
-        "path" attributes. The latter is giving the full path of the library .so file.
-
-        Example:
-
-        <library name="name" path="/vendor/lib/soundfx/lib.so"/>
-
-      </xs:documentation>
-    </xs:annotation>
-    <xs:sequence>
-      <xs:element name="library" minOccurs="0" maxOccurs="unbounded">
-        <xs:complexType>
-          <xs:attribute name="name" type="xs:string" use="required"/>
-          <xs:attribute name="path" type="xs:string" use="required"/>
-        </xs:complexType>
-      </xs:element>
-    </xs:sequence>
-  </xs:complexType>
-  <xs:complexType name="effectImplType">
-    <xs:attribute name="library" type="xs:string" use="required"/>
-    <xs:attribute name="uuid" type="aec:uuidType" use="required"/>
-  </xs:complexType>
-  <xs:complexType name="effectProxyType">
-    <xs:complexContent>
-      <xs:extension base="aec:effectImplType">
-        <xs:sequence>
-          <xs:element name="libsw" type="aec:effectImplType" minOccurs="0" maxOccurs="1"/>
-          <xs:element name="libhw" type="aec:effectImplType" minOccurs="0" maxOccurs="1"/>
-        </xs:sequence>
-        <xs:attribute name="name" type="xs:string" use="required"/>
-      </xs:extension>
-    </xs:complexContent>
-  </xs:complexType>
-  <xs:complexType name="effectType">
-    <xs:annotation>
-      <xs:documentation xml:lang="en">
-        List of effects to load. Each effect element must contain "name",
-        "library", and "uuid" attrs. The value of the "library" attr must
-        correspond to the name of a "library" element. The name of the effect
-        element is indicative, only the value of the "uuid" element designates
-        the effect for the audio framework.  The uuid is the implementation
-        specific UUID as specified by the effect vendor. This is not the generic
-        effect type UUID.
-
-        For effect proxy implementations, SW and HW implemetations of the effect
-        can be specified.
-
-        Example:
-
-        <effect name="name" library="lib" uuid="uuuu"/>
-        <effect name="proxied" library="proxy" uuid="xxxx">
-            <libsw library="sw_bundle" uuid="yyyy"/>
-            <libhw library="offload_bundle" uuid="zzzz"/>
-        </effect>
-
-      </xs:documentation>
-    </xs:annotation>
-    <xs:sequence>
-      <xs:element name="effect" type="aec:effectProxyType" minOccurs="0" maxOccurs="unbounded"/>
-    </xs:sequence>
-  </xs:complexType>
-  <xs:complexType name="streamProcessingType">
-    <xs:sequence>
-      <xs:element name="apply" minOccurs="0" maxOccurs="unbounded">
-        <xs:complexType>
-          <xs:attribute name="effect" type="xs:string" use="required"/>
-        </xs:complexType>
-      </xs:element>
-    </xs:sequence>
-  </xs:complexType>
-  <xs:complexType name="streamPreprocessType">
-    <xs:annotation>
-      <xs:documentation xml:lang="en">
-        Audio preprocessing configuration. The processing configuration consists
-        of a list of elements each describing processing settings for a given
-        input stream. Valid input stream types are listed in "streamInputType".
-
-        Each stream element contains a list of "apply" elements. The value of the
-        "effect" attr must correspond to the name of an "effect" element.
-
-        Example:
-
-        <stream type="voice_communication">
-            <apply effect="effect1"/>
-            <apply effect="effect2"/>
-        </stream>
-
-      </xs:documentation>
-    </xs:annotation>
-    <xs:complexContent>
-      <xs:extension base="aec:streamProcessingType">
-        <xs:attribute name="type" type="aec:streamInputType" use="required"/>
-      </xs:extension>
-    </xs:complexContent>
-  </xs:complexType>
-  <xs:complexType name="streamPostprocessType">
-    <xs:annotation>
-      <xs:documentation xml:lang="en">
-        Audio postprocessing configuration. The processing configuration consists
-        of a list of elements each describing processing settings for a given
-        output stream. Valid output stream types are listed in "streamOutputType".
-
-        Each stream element contains a list of "apply" elements. The value of the
-        "effect" attr must correspond to the name of an "effect" element.
-
-        Example:
-
-        <stream type="music">
-            <apply effect="effect1"/>
-        </stream>
-
-      </xs:documentation>
-    </xs:annotation>
-    <xs:complexContent>
-      <xs:extension base="aec:streamProcessingType">
-        <xs:attribute name="type" type="aec:streamOutputType" use="required"/>
-      </xs:extension>
-    </xs:complexContent>
-  </xs:complexType>
-
-  <!-- Root element -->
-  <xs:element name="audio_effects_conf">
-    <xs:complexType>
-      <xs:sequence>
-        <xs:element name="libraries" type="aec:libraryType"/>
-        <xs:element name="effects" type="aec:effectType"/>
-        <xs:element name="postprocess" minOccurs="0" maxOccurs="1">
-          <xs:complexType>
-            <xs:sequence>
-              <xs:element name="stream" type="aec:streamPostprocessType" minOccurs="0" maxOccurs="unbounded"/>
-            </xs:sequence>
-          </xs:complexType>
-        </xs:element>
-        <xs:element name="preprocess" minOccurs="0" maxOccurs="1">
-          <xs:complexType>
-            <xs:sequence>
-              <xs:element name="stream" type="aec:streamPreprocessType" minOccurs="0" maxOccurs="unbounded"/>
-            </xs:sequence>
-          </xs:complexType>
-        </xs:element>
-      </xs:sequence>
-      <xs:attribute name="version" type="aec:versionType" use="required"/>
-    </xs:complexType>
-
-    <!-- Keys and references -->
-    <xs:key name="libraryName">
-      <xs:selector xpath="aec:libraries/aec:library"/>
-      <xs:field xpath="@name"/>
-    </xs:key>
-    <xs:keyref name="libraryNameRef1" refer="aec:libraryName">
-      <xs:selector xpath="aec:effects/aec:effect"/>
-      <xs:field xpath="@library"/>
-    </xs:keyref>
-    <xs:keyref name="libraryNameRef2" refer="aec:libraryName">
-      <xs:selector xpath="aec:effects/aec:effect/aec:libsw"/>
-      <xs:field xpath="@library"/>
-    </xs:keyref>
-    <xs:keyref name="libraryNameRef3" refer="aec:libraryName">
-      <xs:selector xpath="aec:effects/aec:effect/aec:libhw"/>
-      <xs:field xpath="@library"/>
-    </xs:keyref>
-    <xs:key name="effectName">
-      <xs:selector xpath="aec:effects/aec:effect"/>
-      <xs:field xpath="@name"/>
-    </xs:key>
-    <xs:keyref name="effectNamePreRef" refer="aec:effectName">
-      <xs:selector xpath="aec:preprocess/aec:stream/aec:apply"/>
-      <xs:field xpath="@effect"/>
-    </xs:keyref>
-    <xs:keyref name="effectNamePostRef" refer="aec:effectName">
-      <xs:selector xpath="aec:postprocess/aec:stream/aec:apply"/>
-      <xs:field xpath="@effect"/>
-    </xs:keyref>
-  </xs:element>
-</xs:schema>
diff --git a/automotive/evs/1.0/vts/functional/VtsEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsEvsV1_0TargetTest.cpp
index 2e80afe..57050d7 100644
--- a/automotive/evs/1.0/vts/functional/VtsEvsV1_0TargetTest.cpp
+++ b/automotive/evs/1.0/vts/functional/VtsEvsV1_0TargetTest.cpp
@@ -17,8 +17,13 @@
 #define LOG_TAG "VtsHalEvsTest"
 
 
-// TODO:  How should we configure these values to target appropriate hardware?
-const static char kEnumeratorName[]  = "EvsEnumeratorHw-Mock";
+// Note:  We have't got a great way to indicate which target
+// should be tested, so we'll leave the interface served by the
+// default (mock) EVS driver here for easy reference.  All
+// actual EVS drivers should serve on the EvsEnumeratorHw name,
+// however, so the code is checked in that way.
+//const static char kEnumeratorName[]  = "EvsEnumeratorHw-Mock";
+const static char kEnumeratorName[]  = "EvsEnumeratorHw";
 
 
 // These values are called out in the EVS design doc (as of Mar 8, 2017)
@@ -474,4 +479,4 @@
 
     // Explicitly release the display
     pEnumerator->closeDisplay(pDisplay);
-}
\ No newline at end of file
+}
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.cpp b/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.cpp
index 46e062b..4faccbd 100644
--- a/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/EmulatedVehicleHal.cpp
@@ -189,6 +189,7 @@
         timestamps.push_back(freezeFrame.timestamp);
     }
     outValue->value.int64Values = timestamps;
+    outValue->prop = OBD2_FREEZE_FRAME_INFO;
     return V2_0::StatusCode::OK;
 }
 
diff --git a/automotive/vehicle/2.1/types.hal b/automotive/vehicle/2.1/types.hal
index 2d1aa46..54e87ed 100644
--- a/automotive/vehicle/2.1/types.hal
+++ b/automotive/vehicle/2.1/types.hal
@@ -45,6 +45,42 @@
       | VehicleArea:GLOBAL),
 
     /**
+     * Automatic re-circulation on/off
+     *
+     * IVehicle#set may return StatusCode::NOT_AVAILABLE and IVehicle#get is not
+     * guaranteed to work if HVAC unit is off.  See HVAC_POWER_ON property for
+     * details.
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    HVAC_AUTO_RECIRC_ON = (
+        0x0512
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:BOOLEAN
+        | VehicleArea:ZONE),
+
+    /**
+     * Vehicle Maps Service (VMS) message
+     *
+     * This property uses COMPLEX data to communicate vms messages.
+     *
+     * Its contents are to be interpreted as follows:
+     * the indices defined in VmsMessageIntegerValuesIndex are to be used to
+     * read from int32Values;
+     * bytes is a serialized VMS message as defined in the vms protocol
+     * which is opaque to the framework;
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    VEHICLE_MAP_SERVICE = (
+        0x0C00
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:COMPLEX
+        | VehicleArea:GLOBAL),
+
+    /**
      * OBD2 Live Sensor Data
      *
      * This property uses COMPLEX data to send a snapshot of the current (live)
@@ -174,26 +210,6 @@
       | VehiclePropertyGroup:SYSTEM
       | VehiclePropertyType:COMPLEX
       | VehicleArea:GLOBAL),
-
-    /**
-     * Vehicle Maps Service (VMS) message
-     *
-     * This property uses COMPLEX data to communicate vms messages.
-     *
-     * Its contents are to be interpreted as follows:
-     * the indices defined in VmsMessageIntegerValuesIndex are to be used to
-     * read from int32Values;
-     * bytes is a serialized VMS message as defined in the vms protocol
-     * which is opaque to the framework;
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     */
-    VEHICLE_MAP_SERVICE = (
-        0x0C00
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:COMPLEX
-        | VehicleArea:GLOBAL),
 };
 
 /** The status of a fuel system as described by the OBD2 specification. */
diff --git a/bluetooth/1.0/default/bluetooth_address.cc b/bluetooth/1.0/default/bluetooth_address.cc
index 656d78d..65dc6a6 100644
--- a/bluetooth/1.0/default/bluetooth_address.cc
+++ b/bluetooth/1.0/default/bluetooth_address.cc
@@ -16,8 +16,8 @@
 
 #include "bluetooth_address.h"
 
-#include <android-base/logging.h>
 #include <cutils/properties.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <utils/Log.h>
 
@@ -54,19 +54,25 @@
 
     addr_fd = open(property, O_RDONLY);
     if (addr_fd != -1) {
-      int bytes_read = read(addr_fd, property, kStringLength);
-      CHECK(bytes_read == kStringLength);
+      char address[kStringLength + 1] = {0};
+      int bytes_read = read(addr_fd, address, kStringLength);
+      if (bytes_read == -1) {
+        ALOGE("%s: Error reading address from %s: %s", __func__, property,
+              strerror(errno));
+      }
       close(addr_fd);
 
       // Null terminate the string.
-      property[kStringLength] = '\0';
+      address[kStringLength] = '\0';
 
       // If the address is not all zeros, then use it.
       const uint8_t zero_bdaddr[kBytes] = {0, 0, 0, 0, 0, 0};
-      if ((string_to_bytes(property, local_addr)) &&
+      if ((string_to_bytes(address, local_addr)) &&
           (memcmp(local_addr, zero_bdaddr, kBytes) != 0)) {
         valid_bda = true;
-        ALOGD("%s: Got Factory BDA %s", __func__, property);
+        ALOGD("%s: Got Factory BDA %s", __func__, address);
+      } else {
+        ALOGE("%s: Got Invalid BDA '%s' from %s", __func__, address, property);
       }
     }
   }
diff --git a/bluetooth/1.0/default/h4_protocol.cc b/bluetooth/1.0/default/h4_protocol.cc
index 8f24b5e..2008b00 100644
--- a/bluetooth/1.0/default/h4_protocol.cc
+++ b/bluetooth/1.0/default/h4_protocol.cc
@@ -17,9 +17,11 @@
 #include "h4_protocol.h"
 
 #define LOG_TAG "android.hardware.bluetooth-hci-h4"
-#include <android-base/logging.h>
-#include <assert.h>
+
+#include <errno.h>
 #include <fcntl.h>
+#include <log/log.h>
+#include <sys/uio.h>
 
 namespace android {
 namespace hardware {
@@ -27,11 +29,20 @@
 namespace hci {
 
 size_t H4Protocol::Send(uint8_t type, const uint8_t* data, size_t length) {
-  int rv = WriteSafely(uart_fd_, &type, sizeof(type));
-  if (rv == sizeof(type)) {
-    rv = WriteSafely(uart_fd_, data, length);
+  struct iovec iov[] = {{&type, sizeof(type)},
+                        {const_cast<uint8_t*>(data), length}};
+  ssize_t ret = 0;
+  do {
+    ret = TEMP_FAILURE_RETRY(writev(uart_fd_, iov, sizeof(iov) / sizeof(iov[0])));
+  } while (-1 == ret && EAGAIN == errno);
+
+  if (ret == -1) {
+    ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+  } else if (ret < static_cast<ssize_t>(length + 1)) {
+    ALOGE("%s: %d / %d bytes written - something went wrong...", __func__,
+          static_cast<int>(ret), static_cast<int>(length + 1));
   }
-  return rv;
+  return ret;
 }
 
 void H4Protocol::OnPacketReady() {
@@ -45,10 +56,9 @@
     case HCI_PACKET_TYPE_SCO_DATA:
       sco_cb_(hci_packetizer_.GetPacket());
       break;
-    default: {
-      bool bad_packet_type = true;
-      CHECK(!bad_packet_type);
-    }
+    default:
+      LOG_ALWAYS_FATAL("%s: Unimplemented packet type %d", __func__,
+                       static_cast<int>(hci_packet_type_));
   }
   // Get ready for the next type byte.
   hci_packet_type_ = HCI_PACKET_TYPE_UNKNOWN;
@@ -57,8 +67,19 @@
 void H4Protocol::OnDataReady(int fd) {
   if (hci_packet_type_ == HCI_PACKET_TYPE_UNKNOWN) {
     uint8_t buffer[1] = {0};
-    size_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
-    CHECK(bytes_read == 1);
+    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
+    if (bytes_read != 1) {
+      if (bytes_read == 0) {
+        LOG_ALWAYS_FATAL("%s: Unexpected EOF reading the packet type!",
+                         __func__);
+      } else if (bytes_read < 0) {
+        LOG_ALWAYS_FATAL("%s: Read packet type error: %s", __func__,
+                         strerror(errno));
+      } else {
+        LOG_ALWAYS_FATAL("%s: More bytes read than expected (%u)!", __func__,
+                         static_cast<unsigned int>(bytes_read));
+      }
+    }
     hci_packet_type_ = static_cast<HciPacketType>(buffer[0]);
   } else {
     hci_packetizer_.OnDataReady(fd, hci_packet_type_);
diff --git a/bluetooth/1.0/default/hci_packetizer.cc b/bluetooth/1.0/default/hci_packetizer.cc
index 9549858..2da1254 100644
--- a/bluetooth/1.0/default/hci_packetizer.cc
+++ b/bluetooth/1.0/default/hci_packetizer.cc
@@ -17,11 +17,11 @@
 #include "hci_packetizer.h"
 
 #define LOG_TAG "android.hardware.bluetooth.hci_packetizer"
-#include <android-base/logging.h>
-#include <utils/Log.h>
 
 #include <dlfcn.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <utils/Log.h>
 
 namespace {
 
@@ -45,15 +45,22 @@
 namespace bluetooth {
 namespace hci {
 
-const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const { return packet_; }
+const hidl_vec<uint8_t>& HciPacketizer::GetPacket() const {
+  return packet_;
+}
 
 void HciPacketizer::OnDataReady(int fd, HciPacketType packet_type) {
   switch (state_) {
     case HCI_PREAMBLE: {
-      size_t bytes_read = TEMP_FAILURE_RETRY(
+      ssize_t bytes_read = TEMP_FAILURE_RETRY(
           read(fd, preamble_ + bytes_read_,
                preamble_size_for_type[packet_type] - bytes_read_));
-      CHECK(bytes_read > 0);
+      if (bytes_read <= 0) {
+        LOG_ALWAYS_FATAL_IF((bytes_read == 0),
+                            "%s: Unexpected EOF reading the header!", __func__);
+        LOG_ALWAYS_FATAL("%s: Read header error: %s", __func__,
+                         strerror(errno));
+      }
       bytes_read_ += bytes_read;
       if (bytes_read_ == preamble_size_for_type[packet_type]) {
         size_t packet_length =
@@ -68,11 +75,17 @@
     }
 
     case HCI_PAYLOAD: {
-      size_t bytes_read = TEMP_FAILURE_RETRY(read(
+      ssize_t bytes_read = TEMP_FAILURE_RETRY(read(
           fd,
           packet_.data() + preamble_size_for_type[packet_type] + bytes_read_,
           bytes_remaining_));
-      CHECK(bytes_read > 0);
+      if (bytes_read <= 0) {
+        LOG_ALWAYS_FATAL_IF((bytes_read == 0),
+                            "%s: Unexpected EOF reading the payload!",
+                            __func__);
+        LOG_ALWAYS_FATAL("%s: Read payload error: %s", __func__,
+                         strerror(errno));
+      }
       bytes_remaining_ -= bytes_read;
       bytes_read_ += bytes_read;
       if (bytes_remaining_ == 0) {
diff --git a/bluetooth/1.0/default/mct_protocol.cc b/bluetooth/1.0/default/mct_protocol.cc
index 813cebd..2a59187 100644
--- a/bluetooth/1.0/default/mct_protocol.cc
+++ b/bluetooth/1.0/default/mct_protocol.cc
@@ -19,7 +19,6 @@
 #include <assert.h>
 
 #define LOG_TAG "android.hardware.bluetooth-hci-mct"
-#include <android-base/logging.h>
 #include <utils/Log.h>
 
 #include <fcntl.h>
@@ -45,7 +44,7 @@
     return WriteSafely(uart_fds_[CH_CMD], data, length);
   if (type == HCI_PACKET_TYPE_ACL_DATA)
     return WriteSafely(uart_fds_[CH_ACL_OUT], data, length);
-  CHECK(type == HCI_PACKET_TYPE_COMMAND || type == HCI_PACKET_TYPE_ACL_DATA);
+  LOG_ALWAYS_FATAL("%s: Unimplemented packet type = %d", __func__, type);
   return 0;
 }
 
diff --git a/bluetooth/1.0/default/test/bluetooth_address_test.cc b/bluetooth/1.0/default/test/bluetooth_address_test.cc
index adcd9c1..e60729e 100644
--- a/bluetooth/1.0/default/test/bluetooth_address_test.cc
+++ b/bluetooth/1.0/default/test/bluetooth_address_test.cc
@@ -15,6 +15,7 @@
 //
 
 #include <cutils/properties.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <gtest/gtest.h>
 
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc
index a291e14..ffc283e 100644
--- a/bluetooth/1.0/default/vendor_interface.cc
+++ b/bluetooth/1.0/default/vendor_interface.cc
@@ -17,7 +17,6 @@
 #include "vendor_interface.h"
 
 #define LOG_TAG "android.hardware.bluetooth@1.0-impl"
-#include <android-base/logging.h>
 #include <cutils/properties.h>
 #include <utils/Log.h>
 
@@ -163,14 +162,16 @@
     InitializeCompleteCallback initialize_complete_cb,
     PacketReadCallback event_cb, PacketReadCallback acl_cb,
     PacketReadCallback sco_cb) {
-  CHECK(!g_vendor_interface);
+  LOG_ALWAYS_FATAL_IF(g_vendor_interface, "%s: No previous Shutdown()?",
+                      __func__);
   g_vendor_interface = new VendorInterface();
   return g_vendor_interface->Open(initialize_complete_cb, event_cb, acl_cb,
                                   sco_cb);
 }
 
 void VendorInterface::Shutdown() {
-  CHECK(g_vendor_interface);
+  LOG_ALWAYS_FATAL_IF(!g_vendor_interface, "%s: No Vendor interface!",
+                      __func__);
   g_vendor_interface->Close();
   delete g_vendor_interface;
   g_vendor_interface = nullptr;
@@ -204,7 +205,9 @@
   // Get the local BD address
 
   uint8_t local_bda[BluetoothAddress::kBytes];
-  CHECK(BluetoothAddress::get_local_address(local_bda));
+  if (!BluetoothAddress::get_local_address(local_bda)) {
+    LOG_ALWAYS_FATAL("%s: No Bluetooth Address!", __func__);
+  }
   int status = lib_interface_->init(&lib_callbacks, (unsigned char*)local_bda);
   if (status) {
     ALOGE("%s unable to initialize vendor library: %d", __func__, status);
diff --git a/bluetooth/1.0/vts/functional/Android.bp b/bluetooth/1.0/vts/functional/Android.bp
index d2e6553..cd2be44 100644
--- a/bluetooth/1.0/vts/functional/Android.bp
+++ b/bluetooth/1.0/vts/functional/Android.bp
@@ -28,7 +28,10 @@
         "libutils",
         "android.hardware.bluetooth@1.0",
     ],
-    static_libs: ["VtsHalHidlTargetTestBase"],
+    static_libs: [
+        "VtsHalHidlTargetTestBase",
+        "libbluetooth-types",
+    ],
     cflags: [
         "-O0",
         "-g",
diff --git a/broadcastradio/1.0/types.hal b/broadcastradio/1.0/types.hal
index 045231d..d165e32 100644
--- a/broadcastradio/1.0/types.hal
+++ b/broadcastradio/1.0/types.hal
@@ -155,7 +155,7 @@
 
 enum MetadataKey : int32_t {
     INVALID      = -1,
-    /** RDS PI                 - string  */
+    /** RDS PI                 - int32_t  */
     RDS_PI       = 0,
     /** RDS PS                 - string */
     RDS_PS       = 1,
@@ -208,7 +208,10 @@
 struct ProgramInfo {
     uint32_t     channel;   /** current channel. (e.g kHz for band type AM_FM) */
     uint32_t     subChannel; /** current sub channel. (FM_HD) */
-    bool         tuned;     /** tuned to a program or not */
+
+    /** Tuned to a program (not a noise). It's the same condition that would stop scan operation. */
+    bool         tuned;
+
     bool         stereo;    /** program is stereo or not */
     bool         digital;   /** digital program or not (e.g HD Radio program) */
     uint32_t     signalStrength; /** signal strength from 0 to 100 */
diff --git a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
index ebeadb1..7241ad4 100644
--- a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
+++ b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
@@ -228,6 +228,7 @@
     bool getProperties();
     bool openTuner();
     bool checkAntenna();
+    BandConfig& getBand(unsigned idx);
 
     static const nsecs_t kConnectCallbacktimeoutNs = seconds_to_nanoseconds(1);
     static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
@@ -237,6 +238,7 @@
     bool skipped;
     sp<IBroadcastRadio> mRadio;
     Properties mHalProperties;
+    bool mHalPropertiesInitialized = false;
     sp<ITuner> mTuner;
     sp<MyCallback> mTunerCallback;
     Mutex mLock;
@@ -280,23 +282,29 @@
 
 bool BroadcastRadioHidlTest::getProperties()
 {
-    if (mHalProperties.bands.size() == 0) {
-        Result halResult = Result::NOT_INITIALIZED;
-        Return<void> hidlReturn =
-                mRadio->getProperties([&](Result result, const Properties& properties) {
-                        halResult = result;
-                        if (result == Result::OK) {
-                            mHalProperties = properties;
-                        }
-                    });
+    if (mHalPropertiesInitialized) return true;
 
-        EXPECT_TRUE(hidlReturn.isOk());
-        EXPECT_EQ(Result::OK, halResult);
-        EXPECT_EQ(Class::AM_FM, mHalProperties.classId);
-        EXPECT_GT(mHalProperties.numTuners, 0u);
+    Result halResult = Result::NOT_INITIALIZED;
+    auto hidlReturn = mRadio->getProperties([&](Result result, const Properties& properties) {
+        halResult = result;
+        if (result == Result::OK) {
+            mHalProperties = properties;
+        }
+    });
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_EQ(Result::OK, halResult);
+    EXPECT_EQ(radioClass, mHalProperties.classId);
+    EXPECT_GT(mHalProperties.numTuners, 0u);
+    if (radioClass == Class::AM_FM) {
         EXPECT_GT(mHalProperties.bands.size(), 0u);
     }
-    return mHalProperties.bands.size() > 0;
+
+    if (hidlReturn.isOk() && halResult == Result::OK) {
+        mHalPropertiesInitialized = true;
+        return true;
+    }
+    return false;
 }
 
 bool BroadcastRadioHidlTest::openTuner()
@@ -306,17 +314,18 @@
     }
     if (mTuner.get() == nullptr) {
         Result halResult = Result::NOT_INITIALIZED;
-        Return<void> hidlReturn =
-                mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
-                                  [&](Result result, const sp<ITuner>& tuner) {
-                        halResult = result;
-                        if (result == Result::OK) {
-                            mTuner = tuner;
-                        }
-                    });
+        auto openCb = [&](Result result, const sp<ITuner>& tuner) {
+            halResult = result;
+            if (result == Result::OK) {
+                mTuner = tuner;
+            }
+        };
+        auto hidlReturn = mRadio->openTuner(getBand(0), true, mTunerCallback, openCb);
         EXPECT_TRUE(hidlReturn.isOk());
         EXPECT_EQ(Result::OK, halResult);
-        EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
+        if (radioClass == Class::AM_FM) {
+            EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
+        }
     }
     EXPECT_NE(nullptr, mTuner.get());
     return nullptr != mTuner.get();
@@ -324,6 +333,8 @@
 
 bool BroadcastRadioHidlTest::checkAntenna()
 {
+    if (radioClass != Class::AM_FM) return true;
+
     BandConfig halConfig;
     Result halResult = Result::NOT_INITIALIZED;
     Return<void> hidlReturn =
@@ -337,6 +348,19 @@
     return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
 }
 
+BandConfig& BroadcastRadioHidlTest::getBand(unsigned idx) {
+    static BandConfig dummyBandConfig = {};
+    if (radioClass == Class::AM_FM) {
+        EXPECT_GT(mHalProperties.bands.size(), idx);
+        if (mHalProperties.bands.size() > idx) {
+            return mHalProperties.bands[idx];
+        } else {
+            return dummyBandConfig;
+        }
+    } else {
+        return dummyBandConfig;
+    }
+}
 
 /**
  * Test IBroadcastRadio::getProperties() method
@@ -344,7 +368,7 @@
  * Verifies that:
  *  - the HAL implements the method
  *  - the method returns 0 (no error)
- *  - the implementation class is AM_FM
+ *  - the implementation class is radioClass
  *  - the implementation supports at least one tuner
  *  - the implementation supports at one band
  */
@@ -383,22 +407,20 @@
  * Test IBroadcastRadio::openTuner() method called twice.
  *
  * Verifies that:
- *  - the openTuner method fails when called for the second time without deleting previous
- *    ITuner instance
+ *  - the openTuner method fails with INVALID_STATE or succeeds when called for the second time
+ *    without deleting previous ITuner instance
  */
 TEST_P(BroadcastRadioHidlTest, OpenTunerTwice) {
     RETURN_IF_SKIPPED;
     EXPECT_TRUE(openTuner());
 
     Result halResult = Result::NOT_INITIALIZED;
-    Return<void> hidlReturn =
-            mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
-                              [&](Result result, const sp<ITuner>&) {
-                    halResult = result;
-                });
+    auto openCb = [&](Result result, const sp<ITuner>&) { halResult = result; };
+    auto hidlReturn = mRadio->openTuner(getBand(0), true, mTunerCallback, openCb);
     EXPECT_TRUE(hidlReturn.isOk());
-    EXPECT_EQ(Result::INVALID_STATE, halResult);
-    EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
+    if (halResult == Result::INVALID_STATE) {
+        EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
+    }
 }
 
 /**
@@ -411,16 +433,17 @@
  *  - the configuration read back from HAl has the same class Id
  */
 TEST_P(BroadcastRadioHidlTest, SetAndGetConfiguration) {
+    if (radioClass != Class::AM_FM) skipped = true;
     RETURN_IF_SKIPPED;
     ASSERT_EQ(true, openTuner());
     // test setConfiguration
     mCallbackCalled = false;
-    Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[1]);
+    Return<Result> hidlResult = mTuner->setConfiguration(getBand(1));
     EXPECT_TRUE(hidlResult.isOk());
     EXPECT_EQ(Result::OK, hidlResult);
     EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
     EXPECT_EQ(Result::OK, mResultCallbackData);
-    EXPECT_EQ(mHalProperties.bands[1], mBandConfigCallbackData);
+    EXPECT_EQ(getBand(1), mBandConfigCallbackData);
 
     // test getConfiguration
     BandConfig halConfig;
@@ -434,7 +457,7 @@
             });
     EXPECT_TRUE(hidlReturn.isOk());
     EXPECT_EQ(Result::OK, halResult);
-    EXPECT_EQ(mHalProperties.bands[1], halConfig);
+    EXPECT_EQ(getBand(1), halConfig);
 }
 
 /**
@@ -445,6 +468,7 @@
  *  - the method recovers and succeeds after passing correct arguments
  */
 TEST_P(BroadcastRadioHidlTest, SetConfigurationFails) {
+    if (radioClass != Class::AM_FM) skipped = true;
     RETURN_IF_SKIPPED;
     ASSERT_EQ(true, openTuner());
 
@@ -463,7 +487,7 @@
 
     // Test setConfiguration recovering after passing good data.
     mCallbackCalled = false;
-    setResult = mTuner->setConfiguration(mHalProperties.bands[0]);
+    setResult = mTuner->setConfiguration(getBand(0));
     EXPECT_TRUE(setResult.isOk());
     EXPECT_EQ(Result::OK, setResult);
     EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
@@ -508,6 +532,7 @@
  *  - skipping sub-channel or not does not fail the call
  */
 TEST_P(BroadcastRadioHidlTest, Step) {
+    if (radioClass != Class::AM_FM) skipped = true;
     RETURN_IF_SKIPPED;
     ASSERT_EQ(true, openTuner());
     ASSERT_TRUE(checkAntenna());
@@ -535,18 +560,21 @@
  *  - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
  */
 TEST_P(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
+    if (radioClass != Class::AM_FM) skipped = true;
     RETURN_IF_SKIPPED;
     ASSERT_EQ(true, openTuner());
     ASSERT_TRUE(checkAntenna());
 
+    auto& band = getBand(0);
+
     // test tune
-    ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u);
-    ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit);
+    ASSERT_GT(band.spacings.size(), 0u);
+    ASSERT_GT(band.upperLimit, band.lowerLimit);
 
     // test scan UP
-    uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit;
-    uint32_t upperLimit = mHalProperties.bands[0].upperLimit;
-    uint32_t spacing = mHalProperties.bands[0].spacings[0];
+    uint32_t lowerLimit = band.lowerLimit;
+    uint32_t upperLimit = band.upperLimit;
+    uint32_t spacing = band.spacings[0];
 
     uint32_t channel =
             lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing;
@@ -571,11 +599,8 @@
     EXPECT_TRUE(hidlReturn.isOk());
     EXPECT_EQ(Result::OK, halResult);
     if (mResultCallbackData == Result::OK) {
-        EXPECT_EQ(true, halInfo.tuned);
         EXPECT_LE(halInfo.channel, upperLimit);
         EXPECT_GE(halInfo.channel, lowerLimit);
-    } else {
-        EXPECT_EQ(false, halInfo.tuned);
     }
 
     // test cancel
@@ -593,6 +618,7 @@
  *  - the method recovers and succeeds after passing correct arguments
  */
 TEST_P(BroadcastRadioHidlTest, TuneFailsOutOfBounds) {
+    if (radioClass != Class::AM_FM) skipped = true;
     RETURN_IF_SKIPPED;
     ASSERT_TRUE(openTuner());
     ASSERT_TRUE(checkAntenna());
diff --git a/broadcastradio/1.1/ITuner.hal b/broadcastradio/1.1/ITuner.hal
index 7511629..912786a 100644
--- a/broadcastradio/1.1/ITuner.hal
+++ b/broadcastradio/1.1/ITuner.hal
@@ -21,6 +21,27 @@
 interface ITuner extends @1.0::ITuner {
 
     /**
+     * Tune to a specified program.
+     *
+     * For AM/FM, it must be called when a valid configuration has been applied.
+     * Automatically cancels pending scan, step or tune.
+     *
+     * If method returns OK, ITunerCallback.tuneComplete_1_1() MUST be called:
+     * - once successfully tuned;
+     * - after a time out;
+     * - after a full band scan, if no station found.
+     *
+     * The tuned field of ProgramInfo should indicate if tuned to a valid
+     * station or not.
+     *
+     * @param program Program to tune to.
+     * @return result OK if successfully started tunning.
+     *                INVALID_ARGUMENTS if invalid arguments are passed.
+     *                NOT_INITIALIZED if another error occurs.
+     */
+    tune_1_1(ProgramSelector program) generates (Result result);
+
+    /**
      * Retrieve current station information.
      * @return result OK if scan successfully started
      *                NOT_INITIALIZED if another error occurs
diff --git a/broadcastradio/1.1/default/Android.bp b/broadcastradio/1.1/default/Android.bp
index 759eb09..bec8524 100644
--- a/broadcastradio/1.1/default/Android.bp
+++ b/broadcastradio/1.1/default/Android.bp
@@ -27,16 +27,18 @@
         "BroadcastRadio.cpp",
         "BroadcastRadioFactory.cpp",
         "Tuner.cpp",
-        "Utils.cpp",
+        "VirtualProgram.cpp",
+        "VirtualRadio.cpp",
+    ],
+    static_libs: [
+        "android.hardware.broadcastradio@1.1-utils-lib",
     ],
     shared_libs: [
         "libhidlbase",
         "libhidltransport",
         "libutils",
         "liblog",
-        "libhardware",
         "android.hardware.broadcastradio@1.0",
         "android.hardware.broadcastradio@1.1",
-        "libradio_metadata",
     ],
 }
diff --git a/broadcastradio/1.1/default/BroadcastRadio.cpp b/broadcastradio/1.1/default/BroadcastRadio.cpp
index d65fe6d..3aac127 100644
--- a/broadcastradio/1.1/default/BroadcastRadio.cpp
+++ b/broadcastradio/1.1/default/BroadcastRadio.cpp
@@ -13,14 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "BroadcastRadio"
-//#define LOG_NDEBUG 0
-
-#include <log/log.h>
+#define LOG_TAG "BroadcastRadioDefault.module"
+#define LOG_NDEBUG 0
 
 #include "BroadcastRadio.h"
-#include "Tuner.h"
-#include "Utils.h"
+
+#include <log/log.h>
 
 namespace android {
 namespace hardware {
@@ -28,125 +26,126 @@
 namespace V1_1 {
 namespace implementation {
 
-using ::android::sp;
+using V1_0::Band;
+using V1_0::BandConfig;
+using V1_0::Class;
+using V1_0::Deemphasis;
+using V1_0::Rds;
+
+using std::lock_guard;
+using std::map;
+using std::mutex;
+using std::vector;
+
+// clang-format off
+static const map<Class, ModuleConfig> gModuleConfigs{
+    {Class::AM_FM, ModuleConfig({
+        "Digital radio mock",
+        {  // amFmBands
+            AmFmBandConfig({
+                Band::AM_HD,
+                540,   // lowerLimit
+                1610,  // upperLimit
+                10,    // spacing
+            }),
+            AmFmBandConfig({
+                Band::FM_HD,
+                87900,   // lowerLimit
+                107900,  // upperLimit
+                200,     // spacing
+            }),
+        },
+    })},
+
+    {Class::SAT, ModuleConfig({
+        "Satellite radio mock",
+        {},  // amFmBands
+    })},
+};
+// clang-format on
 
 BroadcastRadio::BroadcastRadio(Class classId)
-        : mStatus(Result::NOT_INITIALIZED), mClassId(classId), mHwDevice(NULL)
-{
+    : mClassId(classId), mConfig(gModuleConfigs.at(classId)) {}
+
+bool BroadcastRadio::isSupported(Class classId) {
+    return gModuleConfigs.find(classId) != gModuleConfigs.end();
 }
 
-BroadcastRadio::~BroadcastRadio()
-{
-    if (mHwDevice != NULL) {
-        radio_hw_device_close(mHwDevice);
-    }
-}
-
-void BroadcastRadio::onFirstRef()
-{
-    const hw_module_t *mod;
-    int rc;
-    ALOGI("%s mClassId %d", __FUNCTION__, mClassId);
-
-    mHwDevice = NULL;
-    const char *classString = Utils::getClassString(mClassId);
-    if (classString == NULL) {
-        ALOGE("invalid class ID %d", mClassId);
-        mStatus = Result::INVALID_ARGUMENTS;
-        return;
-    }
-
-    ALOGI("%s RADIO_HARDWARE_MODULE_ID %s %s",
-            __FUNCTION__, RADIO_HARDWARE_MODULE_ID, classString);
-
-    rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, classString, &mod);
-    if (rc != 0) {
-        ALOGE("couldn't load radio module %s.%s (%s)",
-                RADIO_HARDWARE_MODULE_ID, classString, strerror(-rc));
-        return;
-    }
-    rc = radio_hw_device_open(mod, &mHwDevice);
-    if (rc != 0) {
-        ALOGE("couldn't open radio hw device in %s.%s (%s)",
-                RADIO_HARDWARE_MODULE_ID, "primary", strerror(-rc));
-        mHwDevice = NULL;
-        return;
-    }
-    if (mHwDevice->common.version != RADIO_DEVICE_API_VERSION_CURRENT) {
-        ALOGE("wrong radio hw device version %04x", mHwDevice->common.version);
-        radio_hw_device_close(mHwDevice);
-        mHwDevice = NULL;
-    } else {
-        mStatus = Result::OK;
-    }
-}
-
-int BroadcastRadio::closeHalTuner(const struct radio_tuner *halTuner)
-{
-    ALOGV("%s", __FUNCTION__);
-    if (mHwDevice == NULL) {
-        return -ENODEV;
-    }
-    if (halTuner == 0) {
-        return -EINVAL;
-    }
-    return mHwDevice->close_tuner(mHwDevice, halTuner);
-}
-
-
-// Methods from ::android::hardware::broadcastradio::V1_1::IBroadcastRadio follow.
-Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb)
-{
-    int rc;
-    radio_hal_properties_t halProperties;
-    Properties properties;
-
-    if (mHwDevice == NULL) {
-        rc = -ENODEV;
-        goto exit;
-    }
-    rc = mHwDevice->get_properties(mHwDevice, &halProperties);
-    if (rc == 0) {
-        Utils::convertPropertiesFromHal(&properties, &halProperties);
-    }
-
-exit:
-    _hidl_cb(Utils::convertHalResult(rc), properties);
-    return Void();
+Return<void> BroadcastRadio::getProperties(getProperties_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    return getProperties_1_1(
+        [&](const Properties& properties) { _hidl_cb(Result::OK, properties.base); });
 }
 
 Return<void> BroadcastRadio::getProperties_1_1(getProperties_1_1_cb _hidl_cb) {
-    radio_hal_properties_t halProperties;
-    V1_1::Properties properties = {};
+    ALOGV("%s", __func__);
+    Properties prop11 = {};
+    auto& prop10 = prop11.base;
 
-    LOG_ALWAYS_FATAL_IF(mHwDevice == nullptr, "HW device is not set");
-    int rc = mHwDevice->get_properties(mHwDevice, &halProperties);
-    LOG_ALWAYS_FATAL_IF(rc != 0, "Couldn't get device properties");
-    Utils::convertPropertiesFromHal(&properties.base, &halProperties);
+    prop10.classId = mClassId;
+    prop10.implementor = "Google";
+    prop10.product = mConfig.productName;
+    prop10.numTuners = 1;
+    prop10.numAudioSources = 1;
+    prop10.supportsCapture = false;
+    prop11.supportsBackgroundScanning = false;
+    prop11.vendorExension = "dummy";
 
-    _hidl_cb(properties);
-    return Void();
-}
+    prop10.bands.resize(mConfig.amFmBands.size());
+    for (size_t i = 0; i < mConfig.amFmBands.size(); i++) {
+        auto& src = mConfig.amFmBands[i];
+        auto& dst = prop10.bands[i];
 
-Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio,
-    const sp<V1_0::ITunerCallback>& callback, openTuner_cb _hidl_cb)
-{
-    sp<Tuner> tunerImpl = new Tuner(callback, this);
+        dst.type = src.type;
+        dst.antennaConnected = true;
+        dst.lowerLimit = src.lowerLimit;
+        dst.upperLimit = src.upperLimit;
+        dst.spacings = vector<uint32_t>({src.spacing});
 
-    radio_hal_band_config_t halConfig;
-    const struct radio_tuner *halTuner;
-    Utils::convertBandConfigToHal(&halConfig, &config);
-    int rc = mHwDevice->open_tuner(mHwDevice, &halConfig, audio, Tuner::callback,
-            tunerImpl.get(), &halTuner);
-    if (rc == 0) {
-        tunerImpl->setHalTuner(halTuner);
+        if (src.type == Band::AM) {
+            dst.ext.am.stereo = true;
+        } else if (src.type == Band::FM) {
+            dst.ext.fm.deemphasis = Deemphasis::D75;
+            dst.ext.fm.stereo = true;
+            dst.ext.fm.rds = Rds::US;
+            dst.ext.fm.ta = true;
+            dst.ext.fm.af = true;
+            dst.ext.fm.ea = true;
+        }
     }
 
-    _hidl_cb(Utils::convertHalResult(rc), tunerImpl);
+    _hidl_cb(prop11);
     return Void();
 }
 
-} // namespace implementation
+Return<void> BroadcastRadio::openTuner(const BandConfig& config, bool audio __unused,
+                                       const sp<V1_0::ITunerCallback>& callback,
+                                       openTuner_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+
+    auto oldTuner = mTuner.promote();
+    if (oldTuner != nullptr) {
+        ALOGI("Force-closing previously opened tuner");
+        oldTuner->forceClose();
+        mTuner = nullptr;
+    }
+
+    sp<Tuner> newTuner = new Tuner(callback);
+    mTuner = newTuner;
+    if (mClassId == Class::AM_FM) {
+        auto ret = newTuner->setConfiguration(config);
+        if (ret != Result::OK) {
+            _hidl_cb(Result::INVALID_ARGUMENTS, {});
+            return Void();
+        }
+    }
+
+    _hidl_cb(Result::OK, newTuner);
+    return Void();
+}
+
+}  // namespace implementation
 }  // namespace V1_1
 }  // namespace broadcastradio
 }  // namespace hardware
diff --git a/broadcastradio/1.1/default/BroadcastRadio.h b/broadcastradio/1.1/default/BroadcastRadio.h
index 7de31a0..d98afa7 100644
--- a/broadcastradio/1.1/default/BroadcastRadio.h
+++ b/broadcastradio/1.1/default/BroadcastRadio.h
@@ -16,9 +16,10 @@
 #ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H
 #define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIO_H
 
+#include "Tuner.h"
+
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
 #include <android/hardware/broadcastradio/1.1/types.h>
-#include <hardware/radio.h>
 
 namespace android {
 namespace hardware {
@@ -26,42 +27,48 @@
 namespace V1_1 {
 namespace implementation {
 
-using V1_0::Class;
-using V1_0::BandConfig;
-using V1_0::Properties;
+struct AmFmBandConfig {
+    V1_0::Band type;
+    uint32_t lowerLimit;  // kHz
+    uint32_t upperLimit;  // kHz
+    uint32_t spacing;     // kHz
+};
+
+struct ModuleConfig {
+    std::string productName;
+    std::vector<AmFmBandConfig> amFmBands;
+};
 
 struct BroadcastRadio : public V1_1::IBroadcastRadio {
+    /**
+     * Constructs new broadcast radio module.
+     *
+     * Before calling a constructor with a given classId, it must be checked with isSupported
+     * method first. Otherwise it results in undefined behaviour.
+     *
+     * @param classId type of a radio.
+     */
+    BroadcastRadio(V1_0::Class classId);
 
-    BroadcastRadio(Class classId);
+    /**
+     * Checks, if a given radio type is supported.
+     *
+     * @param classId type of a radio.
+     */
+    static bool isSupported(V1_0::Class classId);
 
-    // Methods from ::android::hardware::broadcastradio::V1_1::IBroadcastRadio follow.
+    // V1_1::IBroadcastRadio methods
     Return<void> getProperties(getProperties_cb _hidl_cb) override;
     Return<void> getProperties_1_1(getProperties_1_1_cb _hidl_cb) override;
-    Return<void> openTuner(const BandConfig& config, bool audio,
-            const sp<V1_0::ITunerCallback>& callback, openTuner_cb _hidl_cb) override;
+    Return<void> openTuner(const V1_0::BandConfig& config, bool audio,
+                           const sp<V1_0::ITunerCallback>& callback,
+                           openTuner_cb _hidl_cb) override;
 
-    // RefBase
-    virtual void onFirstRef() override;
-
-    Result initCheck() { return mStatus; }
-    int closeHalTuner(const struct radio_tuner *halTuner);
-
-private:
-    virtual ~BroadcastRadio();
-
-    static const char * sClassModuleNames[];
-
-    Result convertHalResult(int rc);
-    void convertBandConfigFromHal(BandConfig *config,
-            const radio_hal_band_config_t *halConfig);
-    void convertPropertiesFromHal(Properties *properties,
-            const radio_hal_properties_t *halProperties);
-    void convertBandConfigToHal(radio_hal_band_config_t *halConfig,
-            const BandConfig *config);
-
-    Result mStatus;
-    Class mClassId;
-    struct radio_hw_device *mHwDevice;
+   private:
+    std::mutex mMut;
+    V1_0::Class mClassId;
+    ModuleConfig mConfig;
+    wp<Tuner> mTuner;
 };
 
 }  // namespace implementation
diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.cpp b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
index c8b6c39..c2c1158 100644
--- a/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
+++ b/broadcastradio/1.1/default/BroadcastRadioFactory.cpp
@@ -13,29 +13,51 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "BroadcastRadioDefault.factory"
+#define LOG_NDEBUG 0
+
 #include "BroadcastRadioFactory.h"
+
 #include "BroadcastRadio.h"
 
+#include <log/log.h>
+
 namespace android {
 namespace hardware {
 namespace broadcastradio {
 namespace V1_1 {
 namespace implementation {
 
-// Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow.
-Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb)  {
-    sp<BroadcastRadio> impl = new BroadcastRadio(classId);
-    Result retval = Result::NOT_INITIALIZED;
-    if (impl != 0) {
-        retval = impl->initCheck();
-    }
-    _hidl_cb(retval, impl);
-    return Void();
+using V1_0::Class;
+
+using std::vector;
+
+static const vector<Class> gAllClasses = {
+    Class::AM_FM, Class::SAT, Class::DT,
+};
+
+IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name __unused) {
+    return new BroadcastRadioFactory();
 }
 
+BroadcastRadioFactory::BroadcastRadioFactory() {
+    for (auto&& classId : gAllClasses) {
+        if (!BroadcastRadio::isSupported(classId)) continue;
+        mRadioModules[classId] = new BroadcastRadio(classId);
+    }
+}
 
-IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* /* name */) {
-    return new BroadcastRadioFactory();
+Return<void> BroadcastRadioFactory::connectModule(Class classId, connectModule_cb _hidl_cb) {
+    ALOGV("%s", __func__);
+
+    auto moduleIt = mRadioModules.find(classId);
+    if (moduleIt == mRadioModules.end()) {
+        _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
+    } else {
+        _hidl_cb(Result::OK, moduleIt->second);
+    }
+
+    return Void();
 }
 
 }  // namespace implementation
diff --git a/broadcastradio/1.1/default/BroadcastRadioFactory.h b/broadcastradio/1.1/default/BroadcastRadioFactory.h
index 8eb8514..8b67ac3 100644
--- a/broadcastradio/1.1/default/BroadcastRadioFactory.h
+++ b/broadcastradio/1.1/default/BroadcastRadioFactory.h
@@ -16,6 +16,7 @@
 #ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H
 #define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_BROADCASTRADIOFACTORY_H
 
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
 #include <android/hardware/broadcastradio/1.1/types.h>
 
@@ -25,14 +26,17 @@
 namespace V1_1 {
 namespace implementation {
 
-using V1_0::Class;
+extern "C" IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name);
 
 struct BroadcastRadioFactory : public IBroadcastRadioFactory {
-    // Methods from ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory follow.
-    Return<void> connectModule(Class classId, connectModule_cb _hidl_cb) override;
-};
+    BroadcastRadioFactory();
 
-extern "C" IBroadcastRadioFactory* HIDL_FETCH_IBroadcastRadioFactory(const char* name);
+    // V1_0::IBroadcastRadioFactory methods
+    Return<void> connectModule(V1_0::Class classId, connectModule_cb _hidl_cb) override;
+
+   private:
+    std::map<V1_0::Class, sp<IBroadcastRadio>> mRadioModules;
+};
 
 }  // namespace implementation
 }  // namespace V1_1
diff --git a/broadcastradio/1.1/default/Tuner.cpp b/broadcastradio/1.1/default/Tuner.cpp
index ae5848c..bb07f36 100644
--- a/broadcastradio/1.1/default/Tuner.cpp
+++ b/broadcastradio/1.1/default/Tuner.cpp
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "Tuner"
-//#define LOG_NDEBUG 0
-
-#include <log/log.h>
+#define LOG_TAG "BroadcastRadioDefault.tuner"
+#define LOG_NDEBUG 0
 
 #include "BroadcastRadio.h"
 #include "Tuner.h"
-#include "Utils.h"
-#include <system/RadioMetadataWrapper.h>
+
+#include <Utils.h>
+#include <log/log.h>
 
 namespace android {
 namespace hardware {
@@ -30,199 +29,291 @@
 namespace V1_1 {
 namespace implementation {
 
-void Tuner::onCallback(radio_hal_event_t *halEvent)
-{
-    BandConfig config;
-    ProgramInfo info;
-    hidl_vec<MetaData> metadata;
+using namespace std::chrono_literals;
 
-    if (mCallback != 0) {
-        switch(halEvent->type) {
-        case RADIO_EVENT_CONFIG:
-            Utils::convertBandConfigFromHal(&config, &halEvent->config);
-            mCallback->configChange(Utils::convertHalResult(halEvent->status), config);
-            break;
-        case RADIO_EVENT_ANTENNA:
-            mCallback->antennaStateChange(halEvent->on);
-            break;
-        case RADIO_EVENT_TUNED:
-            Utils::convertProgramInfoFromHal(&info, &halEvent->info);
-            if (mCallback1_1 != nullptr) {
-                mCallback1_1->tuneComplete_1_1(Utils::convertHalResult(halEvent->status), info);
-            }
-            mCallback->tuneComplete(Utils::convertHalResult(halEvent->status), info.base);
-            break;
-        case RADIO_EVENT_METADATA: {
-            uint32_t channel;
-            uint32_t sub_channel;
-            if (radio_metadata_get_channel(halEvent->metadata, &channel, &sub_channel) == 0) {
-                Utils::convertMetaDataFromHal(metadata, halEvent->metadata);
-                mCallback->newMetadata(channel, sub_channel, metadata);
-            }
-            } break;
-        case RADIO_EVENT_TA:
-            mCallback->trafficAnnouncement(halEvent->on);
-            break;
-        case RADIO_EVENT_AF_SWITCH:
-            Utils::convertProgramInfoFromHal(&info, &halEvent->info);
-            if (mCallback1_1 != nullptr) {
-                mCallback1_1->afSwitch_1_1(info);
-            }
-            mCallback->afSwitch(info.base);
-            break;
-        case RADIO_EVENT_EA:
-            mCallback->emergencyAnnouncement(halEvent->on);
-            break;
-        case RADIO_EVENT_HW_FAILURE:
-        default:
-            mCallback->hardwareFailure();
-            break;
-        }
-    }
+using V1_0::Band;
+using V1_0::BandConfig;
+using V1_0::Direction;
+
+using std::chrono::milliseconds;
+using std::lock_guard;
+using std::move;
+using std::mutex;
+using std::sort;
+using std::vector;
+
+const struct {
+    milliseconds config = 50ms;
+    milliseconds scan = 200ms;
+    milliseconds step = 100ms;
+    milliseconds tune = 150ms;
+} gDefaultDelay;
+
+Tuner::Tuner(const sp<V1_0::ITunerCallback>& callback)
+    : mCallback(callback),
+      mCallback1_1(ITunerCallback::castFrom(callback).withDefault(nullptr)),
+      mVirtualFm(make_fm_radio()) {}
+
+void Tuner::forceClose() {
+    lock_guard<mutex> lk(mMut);
+    mIsClosed = true;
+    mThread.cancelAll();
 }
 
-//static
-void Tuner::callback(radio_hal_event_t *halEvent, void *cookie)
-{
-    wp<Tuner> weak(reinterpret_cast<Tuner*>(cookie));
-    sp<Tuner> tuner = weak.promote();
-    if (tuner == 0) return;
-    tuner->onCallback(halEvent);
+Return<Result> Tuner::setConfiguration(const BandConfig& config) {
+    ALOGV("%s", __func__);
+
+    if (config.lowerLimit >= config.upperLimit) return Result::INVALID_ARGUMENTS;
+
+    auto task = [this, config]() {
+        ALOGI("Setting AM/FM config");
+        lock_guard<mutex> lk(mMut);
+
+        mAmfmConfig = move(config);
+        mAmfmConfig.antennaConnected = true;
+        mCurrentProgram = utils::make_selector(mAmfmConfig.type, mAmfmConfig.lowerLimit);
+
+        mIsAmfmConfigSet = true;
+        mCallback->configChange(Result::OK, mAmfmConfig);
+    };
+    mThread.schedule(task, gDefaultDelay.config);
+
+    return Result::OK;
 }
 
-Tuner::Tuner(const sp<V1_0::ITunerCallback>& callback, const wp<BroadcastRadio>& parentDevice)
-        : mHalTuner(NULL), mCallback(callback), mCallback1_1(ITunerCallback::castFrom(callback)),
-        mParentDevice(parentDevice)
-{
-    ALOGV("%s", __FUNCTION__);
-}
+Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb) {
+    ALOGV("%s", __func__);
 
-
-Tuner::~Tuner()
-{
-    ALOGV("%s", __FUNCTION__);
-    const sp<BroadcastRadio> parentDevice = mParentDevice.promote();
-    if (parentDevice != 0) {
-        parentDevice->closeHalTuner(mHalTuner);
+    lock_guard<mutex> lk(mMut);
+    if (mIsAmfmConfigSet) {
+        _hidl_cb(Result::OK, mAmfmConfig);
+    } else {
+        _hidl_cb(Result::NOT_INITIALIZED, {});
     }
-}
-
-// Methods from ::android::hardware::broadcastradio::V1_1::ITuner follow.
-Return<Result> Tuner::setConfiguration(const BandConfig& config)  {
-    ALOGV("%s", __FUNCTION__);
-    if (mHalTuner == NULL) {
-        return Utils::convertHalResult(-ENODEV);
-    }
-    radio_hal_band_config_t halConfig;
-    Utils::convertBandConfigToHal(&halConfig, &config);
-    int rc = mHalTuner->set_configuration(mHalTuner, &halConfig);
-    return Utils::convertHalResult(rc);
-}
-
-Return<void> Tuner::getConfiguration(getConfiguration_cb _hidl_cb)  {
-    int rc;
-    radio_hal_band_config_t halConfig;
-    BandConfig config;
-
-    ALOGV("%s", __FUNCTION__);
-    if (mHalTuner == NULL) {
-        rc = -ENODEV;
-        goto exit;
-    }
-    rc = mHalTuner->get_configuration(mHalTuner, &halConfig);
-    if (rc == 0) {
-        Utils::convertBandConfigFromHal(&config, &halConfig);
-    }
-
-exit:
-    _hidl_cb(Utils::convertHalResult(rc), config);
     return Void();
 }
 
-Return<Result> Tuner::scan(Direction direction, bool skipSubChannel)  {
-    if (mHalTuner == NULL) {
-        return Utils::convertHalResult(-ENODEV);
-    }
-    int rc = mHalTuner->scan(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel);
-    return Utils::convertHalResult(rc);
+// makes ProgramInfo that points to no program
+static ProgramInfo makeDummyProgramInfo(const ProgramSelector& selector) {
+    ProgramInfo info11 = {};
+    auto& info10 = info11.base;
+
+    utils::getLegacyChannel(selector, info10.channel, info10.subChannel);
+    info11.selector = selector;
+    info11.flags |= ProgramInfoFlags::MUTED;
+
+    return info11;
 }
 
-Return<Result> Tuner::step(Direction direction, bool skipSubChannel)  {
-    if (mHalTuner == NULL) {
-        return Utils::convertHalResult(-ENODEV);
+void Tuner::tuneInternalLocked(const ProgramSelector& sel) {
+    VirtualRadio* virtualRadio = nullptr;
+    if (mAmfmConfig.type == Band::FM_HD || mAmfmConfig.type == Band::FM) {
+        virtualRadio = &mVirtualFm;
     }
-    int rc = mHalTuner->step(mHalTuner, static_cast<radio_direction_t>(direction), skipSubChannel);
-    return Utils::convertHalResult(rc);
+
+    VirtualProgram virtualProgram;
+    if (virtualRadio != nullptr && virtualRadio->getProgram(sel, virtualProgram)) {
+        mCurrentProgram = virtualProgram.selector;
+        mCurrentProgramInfo = static_cast<ProgramInfo>(virtualProgram);
+    } else {
+        mCurrentProgram = sel;
+        mCurrentProgramInfo = makeDummyProgramInfo(sel);
+    }
+    mIsTuneCompleted = true;
+
+    mCallback->tuneComplete(Result::OK, mCurrentProgramInfo.base);
+    if (mCallback1_1 != nullptr) {
+        mCallback1_1->tuneComplete_1_1(Result::OK, mCurrentProgramInfo);
+    }
 }
 
-Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel)  {
-    if (mHalTuner == NULL) {
-        return Utils::convertHalResult(-ENODEV);
+Return<Result> Tuner::scan(Direction direction, bool skipSubChannel __unused) {
+    ALOGV("%s", __func__);
+    lock_guard<mutex> lk(mMut);
+    vector<VirtualProgram> list;
+
+    if (mAmfmConfig.type == Band::FM_HD || mAmfmConfig.type == Band::FM) {
+        list = mVirtualFm.getProgramList();
     }
-    int rc = mHalTuner->tune(mHalTuner, channel, subChannel);
-    return Utils::convertHalResult(rc);
+
+    if (list.size() == 0) {
+        mIsTuneCompleted = false;
+        auto task = [this, direction]() {
+            ALOGI("Performing failed scan %s", toString(direction).c_str());
+
+            mCallback->tuneComplete(Result::TIMEOUT, {});
+            if (mCallback1_1 != nullptr) {
+                mCallback1_1->tuneComplete_1_1(Result::TIMEOUT, {});
+            }
+        };
+        mThread.schedule(task, gDefaultDelay.scan);
+
+        return Result::OK;
+    }
+
+    // Not optimal (O(sort) instead of O(n)), but not a big deal here;
+    // also, it's likely that list is already sorted (so O(n) anyway).
+    sort(list.begin(), list.end());
+    auto current = mCurrentProgram;
+    auto found = lower_bound(list.begin(), list.end(), VirtualProgram({current}));
+    if (direction == Direction::UP) {
+        if (found < list.end() - 1) {
+            if (utils::tunesTo(current, found->selector)) found++;
+        } else {
+            found = list.begin();
+        }
+    } else {
+        if (found > list.begin() && found != list.end()) {
+            found--;
+        } else {
+            found = list.end() - 1;
+        }
+    }
+    auto tuneTo = found->selector;
+
+    mIsTuneCompleted = false;
+    auto task = [this, tuneTo, direction]() {
+        ALOGI("Performing scan %s", toString(direction).c_str());
+
+        lock_guard<mutex> lk(mMut);
+        tuneInternalLocked(tuneTo);
+    };
+    mThread.schedule(task, gDefaultDelay.scan);
+
+    return Result::OK;
 }
 
-Return<Result> Tuner::cancel()  {
-    if (mHalTuner == NULL) {
-        return Utils::convertHalResult(-ENODEV);
+Return<Result> Tuner::step(Direction direction, bool skipSubChannel) {
+    ALOGV("%s", __func__);
+    ALOGW_IF(!skipSubChannel, "can't step to next frequency without ignoring subChannel");
+
+    lock_guard<mutex> lk(mMut);
+
+    if (!utils::isAmFm(utils::getType(mCurrentProgram))) {
+        ALOGE("Can't step in anything else than AM/FM");
+        return Result::NOT_INITIALIZED;
     }
-    int rc = mHalTuner->cancel(mHalTuner);
-    return Utils::convertHalResult(rc);
+
+    ALOGW_IF(!mIsAmfmConfigSet, "AM/FM config not set");
+    if (!mIsAmfmConfigSet) return Result::INVALID_STATE;
+    mIsTuneCompleted = false;
+
+    auto task = [this, direction]() {
+        ALOGI("Performing step %s", toString(direction).c_str());
+
+        lock_guard<mutex> lk(mMut);
+
+        auto current = utils::getId(mCurrentProgram, IdentifierType::AMFM_FREQUENCY, 0);
+
+        if (direction == Direction::UP) {
+            current += mAmfmConfig.spacings[0];
+        } else {
+            current -= mAmfmConfig.spacings[0];
+        }
+
+        if (current > mAmfmConfig.upperLimit) current = mAmfmConfig.lowerLimit;
+        if (current < mAmfmConfig.lowerLimit) current = mAmfmConfig.upperLimit;
+
+        tuneInternalLocked(utils::make_selector(mAmfmConfig.type, current));
+    };
+    mThread.schedule(task, gDefaultDelay.step);
+
+    return Result::OK;
 }
 
-Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb)  {
-    ALOGV("%s", __FUNCTION__);
+Return<Result> Tuner::tune(uint32_t channel, uint32_t subChannel) {
+    ALOGV("%s(%d, %d)", __func__, channel, subChannel);
+    Band band;
+    {
+        lock_guard<mutex> lk(mMut);
+        band = mAmfmConfig.type;
+    }
+    return tune_1_1(utils::make_selector(band, channel, subChannel));
+}
+
+Return<Result> Tuner::tune_1_1(const ProgramSelector& sel) {
+    ALOGV("%s(%s)", __func__, toString(sel).c_str());
+
+    lock_guard<mutex> lk(mMut);
+
+    if (utils::isAmFm(utils::getType(mCurrentProgram))) {
+        ALOGW_IF(!mIsAmfmConfigSet, "AM/FM config not set");
+        if (!mIsAmfmConfigSet) return Result::INVALID_STATE;
+
+        auto freq = utils::getId(sel, IdentifierType::AMFM_FREQUENCY);
+        if (freq < mAmfmConfig.lowerLimit || freq > mAmfmConfig.upperLimit) {
+            return Result::INVALID_ARGUMENTS;
+        }
+    }
+
+    mIsTuneCompleted = false;
+    auto task = [this, sel]() {
+        lock_guard<mutex> lk(mMut);
+        tuneInternalLocked(sel);
+    };
+    mThread.schedule(task, gDefaultDelay.tune);
+
+    return Result::OK;
+}
+
+Return<Result> Tuner::cancel() {
+    ALOGV("%s", __func__);
+    mThread.cancelAll();
+    return Result::OK;
+}
+
+Return<void> Tuner::getProgramInformation(getProgramInformation_cb _hidl_cb) {
+    ALOGV("%s", __func__);
     return getProgramInformation_1_1([&](Result result, const ProgramInfo& info) {
         _hidl_cb(result, info.base);
     });
 }
 
-Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb)  {
-    int rc;
-    radio_program_info_t halInfo;
-    RadioMetadataWrapper metadataWrapper(&halInfo.metadata);
-    ProgramInfo info;
+Return<void> Tuner::getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) {
+    ALOGV("%s", __func__);
 
-    ALOGV("%s", __FUNCTION__);
-    if (mHalTuner == NULL) {
-        rc = -ENODEV;
-        goto exit;
+    lock_guard<mutex> lk(mMut);
+    if (mIsTuneCompleted) {
+        _hidl_cb(Result::OK, mCurrentProgramInfo);
+    } else {
+        _hidl_cb(Result::NOT_INITIALIZED, makeDummyProgramInfo(mCurrentProgram));
     }
-
-    rc = mHalTuner->get_program_information(mHalTuner, &halInfo);
-    if (rc == 0) {
-        Utils::convertProgramInfoFromHal(&info, &halInfo);
-    }
-
-exit:
-    _hidl_cb(Utils::convertHalResult(rc), info);
     return Void();
 }
 
 Return<ProgramListResult> Tuner::startBackgroundScan() {
+    ALOGV("%s", __func__);
     return ProgramListResult::UNAVAILABLE;
 }
 
 Return<void> Tuner::getProgramList(const hidl_string& filter __unused, getProgramList_cb _hidl_cb) {
-    hidl_vec<ProgramInfo> pList;
-    // TODO(b/34054813): do the actual implementation.
-    _hidl_cb(ProgramListResult::NOT_STARTED, pList);
+    ALOGV("%s", __func__);
+
+    auto& virtualRadio = mVirtualFm;
+    if (mAmfmConfig.type != Band::FM_HD && mAmfmConfig.type != Band::FM) {
+        _hidl_cb(ProgramListResult::OK, {});
+        return Void();
+    }
+
+    auto list = virtualRadio.getProgramList();
+    _hidl_cb(ProgramListResult::OK, vector<ProgramInfo>(list.begin(), list.end()));
     return Void();
 }
 
 Return<void> Tuner::isAnalogForced(isAnalogForced_cb _hidl_cb) {
-    // TODO(b/34348946): do the actual implementation.
+    ALOGV("%s", __func__);
+    // TODO(b/36864090): implement
     _hidl_cb(Result::INVALID_STATE, false);
     return Void();
 }
 
 Return<Result> Tuner::setAnalogForced(bool isForced __unused) {
-    // TODO(b/34348946): do the actual implementation.
+    ALOGV("%s", __func__);
+    // TODO(b/36864090): implement
     return Result::INVALID_STATE;
 }
 
-} // namespace implementation
+}  // namespace implementation
 }  // namespace V1_1
 }  // namespace broadcastradio
 }  // namespace hardware
diff --git a/broadcastradio/1.1/default/Tuner.h b/broadcastradio/1.1/default/Tuner.h
index 57eafd3..17ee99f 100644
--- a/broadcastradio/1.1/default/Tuner.h
+++ b/broadcastradio/1.1/default/Tuner.h
@@ -16,6 +16,9 @@
 #ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H
 #define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_TUNER_H
 
+#include "VirtualRadio.h"
+
+#include <WorkerThread.h>
 #include <android/hardware/broadcastradio/1.1/ITuner.h>
 #include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
 
@@ -25,20 +28,18 @@
 namespace V1_1 {
 namespace implementation {
 
-using V1_0::Direction;
-
-struct BroadcastRadio;
-
 struct Tuner : public ITuner {
+    Tuner(const sp<V1_0::ITunerCallback>& callback);
 
-    Tuner(const sp<V1_0::ITunerCallback>& callback, const wp<BroadcastRadio>& mParentDevice);
+    void forceClose();
 
-    // Methods from ::android::hardware::broadcastradio::V1_1::ITuner follow.
-    Return<Result> setConfiguration(const BandConfig& config) override;
+    // V1_1::ITuner methods
+    Return<Result> setConfiguration(const V1_0::BandConfig& config) override;
     Return<void> getConfiguration(getConfiguration_cb _hidl_cb) override;
-    Return<Result> scan(Direction direction, bool skipSubChannel) override;
-    Return<Result> step(Direction direction, bool skipSubChannel) override;
+    Return<Result> scan(V1_0::Direction direction, bool skipSubChannel) override;
+    Return<Result> step(V1_0::Direction direction, bool skipSubChannel) override;
     Return<Result> tune(uint32_t channel, uint32_t subChannel) override;
+    Return<Result> tune_1_1(const ProgramSelector& program) override;
     Return<Result> cancel() override;
     Return<void> getProgramInformation(getProgramInformation_cb _hidl_cb) override;
     Return<void> getProgramInformation_1_1(getProgramInformation_1_1_cb _hidl_cb) override;
@@ -47,21 +48,24 @@
     Return<void> isAnalogForced(isAnalogForced_cb _hidl_cb) override;
     Return<Result> setAnalogForced(bool isForced) override;
 
-    static void callback(radio_hal_event_t *halEvent, void *cookie);
-    void onCallback(radio_hal_event_t *halEvent);
+   private:
+    std::mutex mMut;
+    WorkerThread mThread;
+    bool mIsClosed = false;  // TODO(b/36864090): use it
 
-    void setHalTuner(const struct radio_tuner *halTuner) { mHalTuner = halTuner; }
-    const struct radio_tuner *getHalTuner() { return mHalTuner; }
-
-private:
-    ~Tuner();
-
-    const struct radio_tuner *mHalTuner;
     const sp<V1_0::ITunerCallback> mCallback;
     const sp<V1_1::ITunerCallback> mCallback1_1;
-    const wp<BroadcastRadio> mParentDevice;
-};
 
+    VirtualRadio mVirtualFm;
+
+    bool mIsAmfmConfigSet = false;
+    V1_0::BandConfig mAmfmConfig;
+    bool mIsTuneCompleted = false;
+    ProgramSelector mCurrentProgram = {};
+    ProgramInfo mCurrentProgramInfo = {};
+
+    void tuneInternalLocked(const ProgramSelector& sel);
+};
 
 }  // namespace implementation
 }  // namespace V1_1
diff --git a/broadcastradio/1.1/default/Utils.cpp b/broadcastradio/1.1/default/Utils.cpp
deleted file mode 100644
index e21344e..0000000
--- a/broadcastradio/1.1/default/Utils.cpp
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#define LOG_TAG "BroadcastRadioHalUtils"
-//#define LOG_NDEBUG 0
-
-#include <log/log.h>
-#include <system/radio_metadata.h>
-
-#include "Utils.h"
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-using V1_0::Band;
-using V1_0::Deemphasis;
-using V1_0::Direction;
-using V1_0::MetadataKey;
-using V1_0::MetadataType;
-using V1_0::Rds;
-
-const char *Utils::sClassModuleNames[] = {
-    RADIO_HARDWARE_MODULE_ID_FM, /* corresponds to RADIO_CLASS_AM_FM */
-    RADIO_HARDWARE_MODULE_ID_SAT,  /* corresponds to RADIO_CLASS_SAT */
-    RADIO_HARDWARE_MODULE_ID_DT,   /* corresponds to RADIO_CLASS_DT */
-};
-
-// make sure HIDL enum values are aligned with legacy values
-static_assert(RADIO_CLASS_AM_FM == static_cast<int>(Class::AM_FM),
-        "AM/FM class mismatch with legacy");
-static_assert(RADIO_CLASS_SAT == static_cast<int>(Class::SAT),
-        "SAT class mismatch with legacy");
-static_assert(RADIO_CLASS_DT == static_cast<int>(Class::DT),
-        "DT class mismatch with legacy");
-
-static_assert(RADIO_BAND_AM == static_cast<int>(Band::AM),
-        "AM band mismatch with legacy");
-static_assert(RADIO_BAND_FM == static_cast<int>(Band::FM),
-        "FM band mismatch with legacy");
-static_assert(RADIO_BAND_AM_HD == static_cast<int>(Band::AM_HD),
-        "AM HD band mismatch with legacy");
-static_assert(RADIO_BAND_FM_HD == static_cast<int>(Band::FM_HD),
-        "FM HD band mismatch with legacy");
-
-static_assert(RADIO_RDS_NONE == static_cast<int>(Rds::NONE),
-        "RDS NONE mismatch with legacy");
-static_assert(RADIO_RDS_WORLD == static_cast<int>(Rds::WORLD),
-        "RDS WORLD mismatch with legacy");
-static_assert(RADIO_RDS_US == static_cast<int>(Rds::US),
-        "RDS US mismatch with legacy");
-
-static_assert(RADIO_DEEMPHASIS_50 == static_cast<int>(Deemphasis::D50),
-        "De-emphasis 50 mismatch with legacy");
-static_assert(RADIO_DEEMPHASIS_75 == static_cast<int>(Deemphasis::D75),
-        "De-emphasis 75 mismatch with legacy");
-
-static_assert(RADIO_DIRECTION_UP == static_cast<int>(Direction::UP),
-        "Direction Up mismatch with legacy");
-static_assert(RADIO_DIRECTION_DOWN == static_cast<int>(Direction::DOWN),
-        "Direction Up mismatch with legacy");
-
-static_assert(RADIO_METADATA_TYPE_INVALID == static_cast<int>(MetadataType::INVALID),
-        "Metadata type INVALID mismatch with legacy");
-static_assert(RADIO_METADATA_TYPE_INT == static_cast<int>(MetadataType::INT),
-        "Metadata type INT mismatch with legacy");
-static_assert(RADIO_METADATA_TYPE_TEXT == static_cast<int>(MetadataType::TEXT),
-        "Metadata type TEXT mismatch with legacy");
-static_assert(RADIO_METADATA_TYPE_RAW == static_cast<int>(MetadataType::RAW),
-        "Metadata type RAW mismatch with legacy");
-static_assert(RADIO_METADATA_TYPE_CLOCK == static_cast<int>(MetadataType::CLOCK),
-        "Metadata type CLOCK mismatch with legacy");
-
-static_assert(RADIO_METADATA_KEY_INVALID == static_cast<int>(MetadataKey::INVALID),
-        "Metadata key INVALID mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_RDS_PI == static_cast<int>(MetadataKey::RDS_PI),
-        "Metadata key RDS_PI mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_RDS_PS == static_cast<int>(MetadataKey::RDS_PS),
-        "Metadata key RDS_PS mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_RDS_PTY == static_cast<int>(MetadataKey::RDS_PTY),
-        "Metadata key RDS_PTY mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_RBDS_PTY == static_cast<int>(MetadataKey::RBDS_PTY),
-        "Metadata key RBDS_PTY mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_RDS_RT == static_cast<int>(MetadataKey::RDS_RT),
-        "Metadata key RDS_RT mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_TITLE == static_cast<int>(MetadataKey::TITLE),
-        "Metadata key TITLE mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_ARTIST == static_cast<int>(MetadataKey::ARTIST),
-        "Metadata key ARTIST mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_ALBUM == static_cast<int>(MetadataKey::ALBUM),
-        "Metadata key ALBUM mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_GENRE == static_cast<int>(MetadataKey::GENRE),
-        "Metadata key GENRE mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_ICON == static_cast<int>(MetadataKey::ICON),
-        "Metadata key ICON mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_ART == static_cast<int>(MetadataKey::ART),
-        "Metadata key ART mismatch with legacy");
-static_assert(RADIO_METADATA_KEY_CLOCK == static_cast<int>(MetadataKey::CLOCK),
-        "Metadata key CLOCK mismatch with legacy");
-
-
-//static
-const char * Utils::getClassString(Class ClassId)
-{
-    int id = static_cast<int>(ClassId);
-
-    if ((id < 0) ||
-            (id >= NELEM(sClassModuleNames))) {
-        ALOGE("invalid class ID %d", id);
-        return NULL;
-    }
-    return sClassModuleNames[id];
-}
-
-//static
-Result Utils::convertHalResult(int rc)
-{
-    switch (rc) {
-        case 0:
-            return Result::OK;
-        case -EINVAL:
-            return Result::INVALID_ARGUMENTS;
-        case -ENOSYS:
-            return Result::INVALID_STATE;
-        case -ETIMEDOUT:
-            return Result::TIMEOUT;
-        case -ENODEV:
-        default:
-            return Result::NOT_INITIALIZED;
-    }
-}
-
-//static
-void Utils::convertBandConfigFromHal(
-        BandConfig *config,
-        const radio_hal_band_config_t *halConfig)
-{
-
-    config->type = static_cast<Band>(halConfig->type);
-    config->antennaConnected = halConfig->antenna_connected;
-    config->lowerLimit = halConfig->lower_limit;
-    config->upperLimit = halConfig->upper_limit;
-    config->spacings.setToExternal(const_cast<unsigned int *>(&halConfig->spacings[0]),
-            halConfig->num_spacings * sizeof(uint32_t));
-    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
-    config->spacings.resize(halConfig->num_spacings);
-
-    if (config->type == Band::FM) {
-        config->ext.fm.deemphasis = static_cast<Deemphasis>(halConfig->fm.deemphasis);
-        config->ext.fm.stereo = halConfig->fm.stereo;
-        config->ext.fm.rds = static_cast<Rds>(halConfig->fm.rds);
-        config->ext.fm.ta = halConfig->fm.ta;
-        config->ext.fm.af = halConfig->fm.af;
-        config->ext.fm.ea = halConfig->fm.ea;
-    } else {
-        config->ext.am.stereo = halConfig->am.stereo;
-    }
-}
-
-//static
-void Utils::convertPropertiesFromHal(Properties *properties,
-        const radio_hal_properties_t *halProperties)
-{
-    properties->classId = static_cast<Class>(halProperties->class_id);
-    properties->implementor.setToExternal(halProperties->implementor, strlen(halProperties->implementor));
-    properties->product.setToExternal(halProperties->product, strlen(halProperties->product));
-    properties->version.setToExternal(halProperties->version, strlen(halProperties->version));
-    properties->serial.setToExternal(halProperties->serial, strlen(halProperties->serial));
-    properties->numTuners = halProperties->num_tuners;
-    properties->numAudioSources = halProperties->num_audio_sources;
-    properties->supportsCapture = halProperties->supports_capture;
-
-    BandConfig *bands =
-            new BandConfig[halProperties->num_bands];
-    for (size_t i = 0; i < halProperties->num_bands; i++) {
-        convertBandConfigFromHal(&bands[i], &halProperties->bands[i]);
-    }
-    properties->bands.setToExternal(bands, halProperties->num_bands);
-    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
-    properties->bands.resize(halProperties->num_bands);
-    delete[] bands;
-}
-
-//static
-void Utils::convertBandConfigToHal(radio_hal_band_config_t *halConfig, const BandConfig *config)
-{
-    halConfig->type = static_cast<radio_band_t>(config->type);
-    halConfig->antenna_connected = config->antennaConnected;
-    halConfig->lower_limit = config->lowerLimit;
-    halConfig->upper_limit = config->upperLimit;
-    halConfig->num_spacings = config->spacings.size();
-    if (halConfig->num_spacings > RADIO_NUM_SPACINGS_MAX) {
-        halConfig->num_spacings = RADIO_NUM_SPACINGS_MAX;
-    }
-    memcpy(halConfig->spacings, config->spacings.data(),
-           sizeof(uint32_t) * halConfig->num_spacings);
-
-    if (config->type == Band::FM) {
-        halConfig->fm.deemphasis = static_cast<radio_deemphasis_t>(config->ext.fm.deemphasis);
-        halConfig->fm.stereo = config->ext.fm.stereo;
-        halConfig->fm.rds = static_cast<radio_rds_t>(config->ext.fm.rds);
-        halConfig->fm.ta = config->ext.fm.ta;
-        halConfig->fm.af = config->ext.fm.af;
-        halConfig->fm.ea = config->ext.fm.ea;
-    } else {
-        halConfig->am.stereo = config->ext.am.stereo;
-    }
-}
-
-
-//static
-void Utils::convertProgramInfoFromHal(ProgramInfo *info, radio_program_info_t *halInfo)
-{
-    auto &info_1_1 = *info;
-    auto &info_1_0 = info->base;
-
-    info_1_0.channel = halInfo->channel;
-    info_1_0.subChannel = halInfo->sub_channel;
-    info_1_0.tuned = halInfo->tuned;
-    info_1_0.stereo = halInfo->stereo;
-    info_1_0.digital = halInfo->digital;
-    info_1_0.signalStrength = halInfo->signal_strength;
-    convertMetaDataFromHal(info_1_0.metadata, halInfo->metadata);
-    // TODO(b/34348946): add support for HAL 1.1 fields
-    info_1_1.flags = 0;
-}
-
-//static
-int Utils::convertMetaDataFromHal(hidl_vec<MetaData>& metadata, radio_metadata_t *halMetadata)
-{
-    if (halMetadata == NULL) {
-        ALOGE("Invalid argument: halMetadata is NULL");
-        return 0;
-    }
-
-    int count = radio_metadata_get_count(halMetadata);
-    if (count <= 0) {
-        return count;
-    }
-    MetaData *newMetadata = new MetaData[count];
-    int outCount = 0;
-    for (int i = 0; i < count; i++) {
-        radio_metadata_key_t key;
-        radio_metadata_type_t type;
-        void *value;
-        size_t size;
-        if (radio_metadata_get_at_index(halMetadata, i , &key, &type, &value, &size) != 0 ||
-                size == 0) {
-            continue;
-        }
-        switch (type) {
-            case RADIO_METADATA_TYPE_INT: {
-                newMetadata[outCount].intValue = *(static_cast<int32_t *>(value));
-            } break;
-            case RADIO_METADATA_TYPE_TEXT: {
-                newMetadata[outCount].stringValue = static_cast<char *>(value);
-            } break;
-            case RADIO_METADATA_TYPE_RAW: {
-                newMetadata[outCount].rawValue.setToExternal(static_cast<uint8_t *>(value), size);
-                // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
-                newMetadata[outCount].rawValue.resize(size);
-            } break;
-            case RADIO_METADATA_TYPE_CLOCK: {
-                radio_metadata_clock_t *clock = static_cast<radio_metadata_clock_t *>(value);
-                newMetadata[outCount].clockValue.utcSecondsSinceEpoch =
-                        clock->utc_seconds_since_epoch;
-                newMetadata[outCount].clockValue.timezoneOffsetInMinutes =
-                        clock->timezone_offset_in_minutes;
-            } break;
-        }
-        newMetadata[outCount].type = static_cast<MetadataType>(type);
-        newMetadata[outCount].key = static_cast<MetadataKey>(key);
-        outCount++;
-    }
-    metadata.setToExternal(newMetadata, outCount);
-    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
-    metadata.resize(outCount);
-    return outCount;
-}
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
diff --git a/broadcastradio/1.1/default/Utils.h b/broadcastradio/1.1/default/Utils.h
deleted file mode 100644
index 22902ba..0000000
--- a/broadcastradio/1.1/default/Utils.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
-#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
-
-#include <android/hardware/broadcastradio/1.1/types.h>
-#include <hardware/radio.h>
-
-namespace android {
-namespace hardware {
-namespace broadcastradio {
-namespace V1_1 {
-namespace implementation {
-
-using V1_0::Class;
-using V1_0::BandConfig;
-using V1_0::MetaData;
-using V1_0::Properties;
-
-class Utils {
-public:
-    static const char * getClassString(Class ClassId);
-    static Result convertHalResult(int rc);
-    static void convertBandConfigFromHal(BandConfig *config,
-            const radio_hal_band_config_t *halConfig);
-    static void convertPropertiesFromHal(Properties *properties,
-            const radio_hal_properties_t *halProperties);
-    static void convertBandConfigToHal(radio_hal_band_config_t *halConfig,
-            const BandConfig *config);
-    static void convertProgramInfoFromHal(ProgramInfo *info,
-                                          radio_program_info_t *halInfo);
-    static int convertMetaDataFromHal(hidl_vec<MetaData>& metadata,
-                                       radio_metadata_t *halMetadata);
-private:
-    static const char * sClassModuleNames[];
-
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace broadcastradio
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
diff --git a/broadcastradio/1.1/default/VirtualProgram.cpp b/broadcastradio/1.1/default/VirtualProgram.cpp
new file mode 100644
index 0000000..ef8bd1c
--- /dev/null
+++ b/broadcastradio/1.1/default/VirtualProgram.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "VirtualProgram.h"
+
+#include <Utils.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+using V1_0::MetaData;
+using V1_0::MetadataKey;
+using V1_0::MetadataType;
+
+VirtualProgram::operator ProgramInfo() const {
+    ProgramInfo info11 = {};
+    auto& info10 = info11.base;
+
+    utils::getLegacyChannel(selector, info10.channel, info10.subChannel);
+    info11.selector = selector;
+    info10.tuned = true;
+    info10.stereo = true;
+    info10.digital = utils::isDigital(selector);
+    info10.signalStrength = info10.digital ? 100 : 80;
+
+    info10.metadata = hidl_vec<MetaData>({
+        {MetadataType::TEXT, MetadataKey::RDS_PS, {}, {}, programName, {}},
+        {MetadataType::TEXT, MetadataKey::TITLE, {}, {}, songTitle, {}},
+        {MetadataType::TEXT, MetadataKey::ARTIST, {}, {}, songArtist, {}},
+    });
+
+    return info11;
+}
+
+// Defining order on virtual programs, how they appear on band.
+// It's mostly for default implementation purposes, may not be complete or correct.
+bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs) {
+    auto& l = lhs.selector;
+    auto& r = rhs.selector;
+
+    // Two programs with the same primaryId is considered the same.
+    if (l.programType != r.programType) return l.programType < r.programType;
+    if (l.primaryId.type != r.primaryId.type) return l.primaryId.type < r.primaryId.type;
+    if (l.primaryId.value != r.primaryId.value) return l.primaryId.value < r.primaryId.value;
+
+    // A little exception for HD Radio subchannel - we check secondary ID too.
+    if (utils::hasId(l, IdentifierType::HD_SUBCHANNEL) &&
+        utils::hasId(r, IdentifierType::HD_SUBCHANNEL)) {
+        return utils::getId(l, IdentifierType::HD_SUBCHANNEL) <
+               utils::getId(r, IdentifierType::HD_SUBCHANNEL);
+    }
+
+    return false;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.1/default/VirtualProgram.h b/broadcastradio/1.1/default/VirtualProgram.h
new file mode 100644
index 0000000..a4fd72c
--- /dev/null
+++ b/broadcastradio/1.1/default/VirtualProgram.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALPROGRAM_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALPROGRAM_H
+
+#include <android/hardware/broadcastradio/1.1/types.h>
+#include <cstdint>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+struct VirtualProgram {
+    ProgramSelector selector;
+
+    std::string programName = "";
+    std::string songArtist = "";
+    std::string songTitle = "";
+
+    explicit operator ProgramInfo() const;
+    friend bool operator<(const VirtualProgram& lhs, const VirtualProgram& rhs);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALPROGRAM_H
diff --git a/broadcastradio/1.1/default/VirtualRadio.cpp b/broadcastradio/1.1/default/VirtualRadio.cpp
new file mode 100644
index 0000000..acf37a4
--- /dev/null
+++ b/broadcastradio/1.1/default/VirtualRadio.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "VirtualRadio.h"
+
+#include <Utils.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+using V1_0::Band;
+
+using std::lock_guard;
+using std::move;
+using std::mutex;
+using std::vector;
+
+using utils::make_selector;
+
+vector<VirtualProgram> gInitialFmPrograms{
+    {make_selector(Band::FM, 94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
+    {make_selector(Band::FM, 96500), "KOIT", "Celine Dion", "All By Myself"},
+    {make_selector(Band::FM, 97300), "Alice@97.3", "Drops of Jupiter", "Train"},
+    {make_selector(Band::FM, 99700), "99.7 Now!", "The Chainsmokers", "Closer"},
+    {make_selector(Band::FM, 101300), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"},
+    {make_selector(Band::FM, 103700), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"},
+    {make_selector(Band::FM, 106100), "106 KMEL", "Drake", "Marvins Room"},
+};
+
+VirtualRadio::VirtualRadio(VirtualRadio&& o) : mPrograms(move(o.mPrograms)) {}
+
+VirtualRadio::VirtualRadio(vector<VirtualProgram> initialList) : mPrograms(initialList) {}
+
+vector<VirtualProgram> VirtualRadio::getProgramList() {
+    lock_guard<mutex> lk(mMut);
+    return mPrograms;
+}
+
+bool VirtualRadio::getProgram(const ProgramSelector& selector, VirtualProgram& programOut) {
+    lock_guard<mutex> lk(mMut);
+    for (auto&& program : mPrograms) {
+        if (utils::tunesTo(selector, program.selector)) {
+            programOut = program;
+            return true;
+        }
+    }
+    return false;
+}
+
+VirtualRadio make_fm_radio() {
+    return VirtualRadio(gInitialFmPrograms);
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.1/default/VirtualRadio.h b/broadcastradio/1.1/default/VirtualRadio.h
new file mode 100644
index 0000000..23cb06c
--- /dev/null
+++ b/broadcastradio/1.1/default/VirtualRadio.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALRADIO_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALRADIO_H
+
+#include "VirtualProgram.h"
+
+#include <mutex>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+
+class VirtualRadio {
+   public:
+    VirtualRadio(VirtualRadio&& o);
+    VirtualRadio(std::vector<VirtualProgram> initialList);
+
+    std::vector<VirtualProgram> getProgramList();
+    bool getProgram(const ProgramSelector& selector, VirtualProgram& program);
+
+   private:
+    std::mutex mMut;
+    std::vector<VirtualProgram> mPrograms;
+};
+
+VirtualRadio make_fm_radio();
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_VIRTUALRADIO_H
diff --git a/broadcastradio/1.1/tests/Android.bp b/broadcastradio/1.1/tests/Android.bp
new file mode 100644
index 0000000..fa1fd94
--- /dev/null
+++ b/broadcastradio/1.1/tests/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "android.hardware.broadcastradio@1.1-utils-tests",
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "WorkerThread_test.cpp",
+    ],
+    static_libs: ["android.hardware.broadcastradio@1.1-utils-lib"],
+}
diff --git a/broadcastradio/1.1/tests/WorkerThread_test.cpp b/broadcastradio/1.1/tests/WorkerThread_test.cpp
new file mode 100644
index 0000000..a0e0ebb
--- /dev/null
+++ b/broadcastradio/1.1/tests/WorkerThread_test.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <WorkerThread.h>
+#include <gtest/gtest.h>
+
+namespace {
+
+using namespace std::chrono_literals;
+
+using android::WorkerThread;
+
+using std::atomic;
+using std::chrono::time_point;
+using std::chrono::steady_clock;
+using std::is_sorted;
+using std::lock_guard;
+using std::mutex;
+using std::this_thread::sleep_for;
+using std::vector;
+
+#define ASSERT_EQ_WITH_TOLERANCE(val1, val2, tolerance) \
+    ASSERT_LE((val1) - (tolerance), (val2));            \
+    ASSERT_GE((val1) + (tolerance), (val2));
+
+TEST(WorkerThreadTest, oneTask) {
+    atomic<bool> executed(false);
+    atomic<time_point<steady_clock>> stop;
+    WorkerThread thread;
+
+    auto start = steady_clock::now();
+    thread.schedule(
+        [&]() {
+            stop = steady_clock::now();
+            executed = true;
+        },
+        100ms);
+
+    sleep_for(150ms);
+
+    ASSERT_TRUE(executed);
+    auto delta = stop.load() - start;
+    ASSERT_EQ_WITH_TOLERANCE(delta, 100ms, 50ms);
+}
+
+TEST(WorkerThreadTest, cancelSecond) {
+    atomic<bool> executed1(false);
+    atomic<bool> executed2(false);
+    WorkerThread thread;
+
+    thread.schedule([&]() { executed2 = true; }, 100ms);
+    thread.schedule([&]() { executed1 = true; }, 25ms);
+
+    sleep_for(50ms);
+    thread.cancelAll();
+    sleep_for(100ms);
+
+    ASSERT_TRUE(executed1);
+    ASSERT_FALSE(executed2);
+}
+
+TEST(WorkerThreadTest, executeInOrder) {
+    mutex mut;
+    vector<int> order;
+    WorkerThread thread;
+
+    thread.schedule(
+        [&]() {
+            lock_guard<mutex> lk(mut);
+            order.push_back(0);
+        },
+        50ms);
+
+    thread.schedule(
+        [&]() {
+            lock_guard<mutex> lk(mut);
+            order.push_back(4);
+        },
+        400ms);
+
+    thread.schedule(
+        [&]() {
+            lock_guard<mutex> lk(mut);
+            order.push_back(1);
+        },
+        100ms);
+
+    thread.schedule(
+        [&]() {
+            lock_guard<mutex> lk(mut);
+            order.push_back(3);
+        },
+        300ms);
+
+    thread.schedule(
+        [&]() {
+            lock_guard<mutex> lk(mut);
+            order.push_back(2);
+        },
+        200ms);
+
+    sleep_for(500ms);
+
+    ASSERT_EQ(5u, order.size());
+    ASSERT_TRUE(is_sorted(order.begin(), order.end()));
+}
+
+TEST(WorkerThreadTest, dontExecuteAfterDestruction) {
+    atomic<bool> executed1(false);
+    atomic<bool> executed2(false);
+    {
+        WorkerThread thread;
+
+        thread.schedule([&]() { executed2 = true; }, 100ms);
+        thread.schedule([&]() { executed1 = true; }, 25ms);
+
+        sleep_for(50ms);
+    }
+    sleep_for(100ms);
+
+    ASSERT_TRUE(executed1);
+    ASSERT_FALSE(executed2);
+}
+
+}  // anonymous namespace
diff --git a/broadcastradio/1.1/types.hal b/broadcastradio/1.1/types.hal
index 5577ea0..dee38b8 100644
--- a/broadcastradio/1.1/types.hal
+++ b/broadcastradio/1.1/types.hal
@@ -68,11 +68,156 @@
 };
 
 /**
+ * Type of a radio technology.
+ *
+ * All other values are reserved for future use.
+ */
+enum ProgramType : uint32_t {
+    AM = 1,  // analogue AM radio (with or without RDS)
+    FM,      // analogue FM radio (with or without RDS)
+    AM_HD,   // AM HD Radio
+    FM_HD,   // FM HD Radio
+    DAB,     // Digital audio broadcasting
+    DRMO,    // Digital Radio Mondiale
+    SXM,     // SiriusXM Satellite Radio
+    VENDOR,  // vendor-specific, not synced across devices
+};
+
+/**
+ * Type of program identifier component.
+ *
+ * It MUST match the radio technology for primary ID but does not have to match
+ * it for secondary IDs. For example, a satellite program may set AM/FM fallback
+ * frequency, if a station broadcasts both via satellite and AM/FM.
+ *
+ * The value format for each (but VENDOR_PRIMARY) identifier is strictly defined
+ * to maintain interoperability between devices made by different vendors.
+ *
+ * All other values are reserved for future use.
+ */
+enum IdentifierType : uint32_t {
+    AMFM_FREQUENCY = 1,  // kHz
+    RDS_PI,              // 16bit
+
+    /**
+     * 64bit compound primary identifier for HD Radio.
+     *
+     * Consists of (from the LSB):
+     * - 32bit: Station ID number;
+     * - 4bit: HD_SUBCHANNEL;
+     * - 18bit: AMFM_FREQUENCY.
+     * The remaining bits should be set to zeros when writing on the chip side
+     * and ignored when read.
+     */
+    HD_STATION_ID_EXT,
+
+    /**
+     * HD Radio subchannel - a value of range 0-7.
+     *
+     * The subchannel index is 0-based (where 0 is MPS and 1..7 are SPS),
+     * as opposed to HD Radio standard (where it's 1-based).
+     */
+    HD_SUBCHANNEL,
+
+    /**
+     * 24bit compound primary identifier for DAB.
+     *
+     * Consists of (from the LSB):
+     * - 16bit: SId;
+     * - 8bit: ECC code.
+     * The remaining bits should be set to zeros when writing on the chip side
+     * and ignored when read.
+     */
+    DAB_SIDECC,
+
+    DAB_ENSEMBLE,     // 16bit
+    DAB_SCID,         // 12bit
+    DAB_FREQUENCY,    // kHz
+    DRMO_SERVICE_ID,  // 24bit
+    DRMO_FREQUENCY,   // kHz
+    SXM_SERVICE_ID,   // 32bit
+    SXM_CHANNEL,      // 0-999 range
+
+    /**
+     * Primary identifier for vendor-specific radio technology.
+     * The value format is determined by a vendor.
+     *
+     * It must not be used in any other programType than VENDOR.
+     */
+    VENDOR_PRIMARY,
+};
+
+/**
+ * A single program identifier component, eg. frequency or channel ID.
+ *
+ * The uint32_t type field maps to IdentifierType enum. It's not straight,
+ * because the enum may be extended in future versions of the HAL. Values out of
+ * the enum range must not be used when writing and ignored when reading.
+ *
+ * The uint64_t value field holds the value in format described in comments for
+ * IdentifierType enum.
+ */
+struct ProgramIdentifier {
+    uint32_t type;  // IdentifierType
+    uint64_t value;
+};
+
+/**
+ * A set of identifiers necessary to tune to a given station.
+ *
+ * This can hold various identifiers, like
+ * - AM/FM frequency
+ * - HD Radio subchannel
+ * - DAB channel info
+ *
+ * The uint32_t programType field maps to ProgramType enum. It's not straight,
+ * because the enum may be extended in future versions of the HAL. Values out of
+ * the enum range must not be used when writing and ignored when reading.
+ *
+ * The primary ID uniquely identifies a station and can be used for equality
+ * check. The secondary IDs are supplementary and can speed up tuning process,
+ * but the primary ID is sufficient (ie. after a full band scan).
+ *
+ * Two selectors with different secondary IDs, but the same primary ID are
+ * considered equal. In particular, secondary IDs vector may get updated for
+ * an entry on the program list (ie. when a better frequency for a given
+ * station is found).
+ *
+ * The primaryId of a given programType MUST be of a specific type:
+ * - AM, FM: RDS_PI if the station broadcasts RDS, AMFM_FREQUENCY otherwise;
+ * - AM_HD, FM_HD: HD_STATION_ID_EXT;
+ * - DAB: DAB_SIDECC;
+ * - DRMO: DRMO_SERVICE_ID;
+ * - SXM: SXM_SERVICE_ID;
+ * - VENDOR: VENDOR_PRIMARY.
+ */
+struct ProgramSelector {
+    uint32_t programType;  // ProgramType
+    ProgramIdentifier primaryId;  // uniquely identifies a station
+    vec<ProgramIdentifier> secondaryIds;
+
+    /**
+     * Opaque vendor-specific identifiers, to be passed to front-end
+     * without changes.
+     *
+     * The order is meaningful, ie. the first element may be defined as
+     * frequency, second as the subchannel etc.
+     *
+     * The vector is not serialized (either locally or to the cloud),
+     * unless it's a VENDOR program type.
+     */
+    vec<uint64_t> vendorIds;
+};
+
+/**
  * Radio program information. Returned by the HAL with event RADIO_EVENT_TUNED.
  * Contains information on currently tuned channel.
  */
 struct ProgramInfo {
     @1.0::ProgramInfo base;
+
+    ProgramSelector selector;
+
     bitfield<ProgramInfoFlags> flags;
 
     /**
diff --git a/broadcastradio/1.1/utils/Android.bp b/broadcastradio/1.1/utils/Android.bp
new file mode 100644
index 0000000..df5e8e0
--- /dev/null
+++ b/broadcastradio/1.1/utils/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.broadcastradio@1.1-utils-lib",
+    vendor: true,
+    relative_install_path: "hw",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+    ],
+    srcs: [
+        "Utils.cpp",
+        "WorkerThread.cpp",
+    ],
+    export_include_dirs: ["."],
+    shared_libs: [
+        "android.hardware.broadcastradio@1.1",
+    ],
+}
diff --git a/broadcastradio/1.1/utils/Utils.cpp b/broadcastradio/1.1/utils/Utils.cpp
new file mode 100644
index 0000000..9dc0a53
--- /dev/null
+++ b/broadcastradio/1.1/utils/Utils.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "BroadcastRadioDefault.utils"
+//#define LOG_NDEBUG 0
+
+#include "Utils.h"
+
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+namespace utils {
+
+using V1_0::Band;
+
+static bool isCompatibleProgramType(const uint32_t ia, const uint32_t ib) {
+    auto a = static_cast<ProgramType>(ia);
+    auto b = static_cast<ProgramType>(ib);
+
+    if (a == b) return true;
+    if (a == ProgramType::AM && b == ProgramType::AM_HD) return true;
+    if (a == ProgramType::AM_HD && b == ProgramType::AM) return true;
+    if (a == ProgramType::FM && b == ProgramType::FM_HD) return true;
+    if (a == ProgramType::FM_HD && b == ProgramType::FM) return true;
+    return false;
+}
+
+static bool bothHaveId(const ProgramSelector& a, const ProgramSelector& b,
+                       const IdentifierType type) {
+    return hasId(a, type) && hasId(b, type);
+}
+
+static bool anyHaveId(const ProgramSelector& a, const ProgramSelector& b,
+                      const IdentifierType type) {
+    return hasId(a, type) || hasId(b, type);
+}
+
+static bool haveEqualIds(const ProgramSelector& a, const ProgramSelector& b,
+                         const IdentifierType type) {
+    if (!bothHaveId(a, b, type)) return false;
+    // TODO(b/36864090): we should check all Ids of a given type (ie. other AF), not just one
+    auto aId = getId(a, type);
+    auto bId = getId(b, type);
+    return aId == bId;
+}
+
+bool tunesTo(const ProgramSelector& a, const ProgramSelector& b) {
+    if (!isCompatibleProgramType(a.programType, b.programType)) return false;
+
+    auto type = getType(a);
+
+    switch (type) {
+        case ProgramType::AM:
+        case ProgramType::AM_HD:
+        case ProgramType::FM:
+        case ProgramType::FM_HD:
+            if (haveEqualIds(a, b, IdentifierType::HD_STATION_ID_EXT)) return true;
+
+            // if HD Radio subchannel is specified, it must match
+            if (anyHaveId(a, b, IdentifierType::HD_SUBCHANNEL)) {
+                // missing subchannel (analog) is an equivalent of first subchannel (MPS)
+                auto aCh = getId(a, IdentifierType::HD_SUBCHANNEL, 0);
+                auto bCh = getId(b, IdentifierType::HD_SUBCHANNEL, 0);
+                if (aCh != bCh) return false;
+            }
+
+            if (haveEqualIds(a, b, IdentifierType::RDS_PI)) return true;
+
+            return haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY);
+        case ProgramType::DAB:
+            return haveEqualIds(a, b, IdentifierType::DAB_SIDECC);
+        case ProgramType::DRMO:
+            return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
+        case ProgramType::SXM:
+            if (anyHaveId(a, b, IdentifierType::SXM_SERVICE_ID)) {
+                return haveEqualIds(a, b, IdentifierType::SXM_SERVICE_ID);
+            }
+            return haveEqualIds(a, b, IdentifierType::SXM_CHANNEL);
+        case ProgramType::VENDOR:
+        default:
+            ALOGW("Unsupported program type: %s", toString(type).c_str());
+            return false;
+    }
+}
+
+ProgramType getType(const ProgramSelector& sel) {
+    return static_cast<ProgramType>(sel.programType);
+}
+
+bool isAmFm(const ProgramType type) {
+    switch (type) {
+        case ProgramType::AM:
+        case ProgramType::FM:
+        case ProgramType::AM_HD:
+        case ProgramType::FM_HD:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool hasId(const ProgramSelector& sel, const IdentifierType type) {
+    auto itype = static_cast<uint32_t>(type);
+    if (sel.primaryId.type == itype) return true;
+    // not optimal, but we don't care in default impl
+    for (auto&& id : sel.secondaryIds) {
+        if (id.type == itype) return true;
+    }
+    return false;
+}
+
+uint64_t getId(const ProgramSelector& sel, const IdentifierType type) {
+    auto itype = static_cast<uint32_t>(type);
+    if (sel.primaryId.type == itype) return sel.primaryId.value;
+    // not optimal, but we don't care in default impl
+    for (auto&& id : sel.secondaryIds) {
+        if (id.type == itype) return id.value;
+    }
+    ALOGW("Identifier %s not found", toString(type).c_str());
+    return 0;
+}
+
+uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval) {
+    if (!hasId(sel, type)) return defval;
+    return getId(sel, type);
+}
+
+ProgramSelector make_selector(Band band, uint32_t channel, uint32_t subChannel) {
+    ProgramSelector sel = {};
+
+    ALOGW_IF((subChannel > 0) && (band == Band::AM || band == Band::FM),
+             "got subChannel for non-HD AM/FM");
+
+    // we can't use ProgramType::AM_HD or FM_HD, because we don't know HD station ID
+    ProgramType type;
+    switch (band) {
+        case Band::AM:
+        case Band::AM_HD:
+            type = ProgramType::AM;
+            break;
+        case Band::FM:
+        case Band::FM_HD:
+            type = ProgramType::FM;
+            break;
+        default:
+            LOG_ALWAYS_FATAL("Unsupported band: %s", toString(band).c_str());
+    }
+
+    sel.programType = static_cast<uint32_t>(type);
+    sel.primaryId.type = static_cast<uint32_t>(IdentifierType::AMFM_FREQUENCY);
+    sel.primaryId.value = channel;
+    if (subChannel > 0) {
+        // stating sub channel for AM/FM channel does not give any guarantees,
+        // but we can't do much more without HD station ID
+        sel.secondaryIds = hidl_vec<ProgramIdentifier>{
+            {static_cast<uint32_t>(IdentifierType::HD_SUBCHANNEL), subChannel},
+        };
+    }
+
+    return sel;
+}
+
+bool getLegacyChannel(const ProgramSelector& sel, uint32_t& channelOut, uint32_t& subChannelOut) {
+    if (isAmFm(getType(sel))) {
+        channelOut = getId(sel, IdentifierType::AMFM_FREQUENCY);
+        subChannelOut = getId(sel, IdentifierType::HD_SUBCHANNEL, 0);
+        return true;
+    } else {
+        channelOut = 0;
+        subChannelOut = 0;
+        return false;
+    }
+}
+
+bool isDigital(const ProgramSelector& sel) {
+    switch (getType(sel)) {
+        case ProgramType::AM:
+        case ProgramType::FM:
+            return false;
+        default:
+            // VENDOR might not be digital, but it doesn't matter for default impl.
+            return true;
+    }
+}
+
+}  // namespace utils
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
diff --git a/broadcastradio/1.1/utils/Utils.h b/broadcastradio/1.1/utils/Utils.h
new file mode 100644
index 0000000..1110e79
--- /dev/null
+++ b/broadcastradio/1.1/utils/Utils.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
+
+#include <android/hardware/broadcastradio/1.1/types.h>
+#include <chrono>
+#include <queue>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace broadcastradio {
+namespace V1_1 {
+namespace implementation {
+namespace utils {
+
+/**
+ * Checks, if {@code pointer} tunes to {@channel}.
+ *
+ * For example, having a channel {AMFM_FREQUENCY = 103.3}:
+ * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 0} can tune to this channel;
+ * - selector {AMFM_FREQUENCY = 103.3, HD_SUBCHANNEL = 1} can't.
+ *
+ * @param pointer selector we're trying to match against channel.
+ * @param channel existing channel.
+ */
+bool tunesTo(const ProgramSelector& pointer, const ProgramSelector& channel);
+
+ProgramType getType(const ProgramSelector& sel);
+bool isAmFm(const ProgramType type);
+
+bool hasId(const ProgramSelector& sel, const IdentifierType type);
+
+/**
+ * Returns ID (either primary or secondary) for a given program selector.
+ *
+ * If the selector does not contain given type, returns 0 and emits a warning.
+ */
+uint64_t getId(const ProgramSelector& sel, const IdentifierType type);
+
+/**
+ * Returns ID (either primary or secondary) for a given program selector.
+ *
+ * If the selector does not contain given type, returns default value.
+ */
+uint64_t getId(const ProgramSelector& sel, const IdentifierType type, uint64_t defval);
+
+ProgramSelector make_selector(V1_0::Band band, uint32_t channel, uint32_t subChannel = 0);
+
+bool getLegacyChannel(const ProgramSelector& sel, uint32_t& channelOut, uint32_t& subChannelOut);
+
+bool isDigital(const ProgramSelector& sel);
+
+}  // namespace utils
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace broadcastradio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_UTILS_H
diff --git a/broadcastradio/1.1/utils/WorkerThread.cpp b/broadcastradio/1.1/utils/WorkerThread.cpp
new file mode 100644
index 0000000..a3ceaa1
--- /dev/null
+++ b/broadcastradio/1.1/utils/WorkerThread.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "WorkerThread"
+//#define LOG_NDEBUG 0
+
+#include "WorkerThread.h"
+
+#include <log/log.h>
+
+namespace android {
+
+using std::chrono::milliseconds;
+using std::chrono::steady_clock;
+using std::function;
+using std::lock_guard;
+using std::mutex;
+using std::priority_queue;
+using std::this_thread::sleep_for;
+using std::unique_lock;
+
+bool operator<(const WorkerThread::Task& lhs, const WorkerThread::Task& rhs) {
+    return lhs.when > rhs.when;
+}
+
+WorkerThread::WorkerThread() : mIsTerminating(false), mThread(&WorkerThread::threadLoop, this) {}
+
+WorkerThread::~WorkerThread() {
+    ALOGV("%s", __func__);
+    {
+        lock_guard<mutex> lk(mMut);
+        mIsTerminating = true;
+        mCond.notify_one();
+    }
+    mThread.join();
+}
+
+void WorkerThread::schedule(function<void()> task, milliseconds delay) {
+    ALOGV("%s", __func__);
+
+    auto when = steady_clock::now() + delay;
+
+    lock_guard<mutex> lk(mMut);
+    mTasks.push(Task({when, task}));
+    mCond.notify_one();
+}
+
+void WorkerThread::cancelAll() {
+    ALOGV("%s", __func__);
+
+    lock_guard<mutex> lk(mMut);
+    priority_queue<Task>().swap(mTasks);  // empty queue
+}
+
+void WorkerThread::threadLoop() {
+    ALOGV("%s", __func__);
+    while (!mIsTerminating) {
+        unique_lock<mutex> lk(mMut);
+        if (mTasks.empty()) {
+            mCond.wait(lk);
+            continue;
+        }
+
+        auto task = mTasks.top();
+        if (task.when > steady_clock::now()) {
+            mCond.wait_until(lk, task.when);
+            continue;
+        }
+
+        mTasks.pop();
+        lk.unlock();  // what() might need to schedule another task
+        task.what();
+    }
+}
+
+}  // namespace android
diff --git a/broadcastradio/1.1/utils/WorkerThread.h b/broadcastradio/1.1/utils/WorkerThread.h
new file mode 100644
index 0000000..635876f
--- /dev/null
+++ b/broadcastradio/1.1/utils/WorkerThread.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_BROADCASTRADIO_V1_1_WORKERTHREAD_H
+#define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_WORKERTHREAD_H
+
+#include <chrono>
+#include <queue>
+#include <thread>
+
+namespace android {
+
+class WorkerThread {
+   public:
+    WorkerThread();
+    virtual ~WorkerThread();
+
+    void schedule(std::function<void()> task, std::chrono::milliseconds delay);
+    void cancelAll();
+
+   private:
+    struct Task {
+        std::chrono::time_point<std::chrono::steady_clock> when;
+        std::function<void()> what;
+    };
+    friend bool operator<(const Task& lhs, const Task& rhs);
+
+    std::atomic<bool> mIsTerminating;
+    std::mutex mMut;
+    std::condition_variable mCond;
+    std::thread mThread;
+    std::priority_queue<Task> mTasks;
+
+    void threadLoop();
+};
+
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_WORKERTHREAD_H
diff --git a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
index aa5ab54..0de6fa5 100644
--- a/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
+++ b/broadcastradio/1.1/vts/functional/VtsHalBroadcastradioV1_1TargetTest.cpp
@@ -48,7 +48,7 @@
 using ::android::hardware::broadcastradio::V1_1::ProgramInfo;
 using ::android::hardware::broadcastradio::V1_1::Result;
 using ::android::hardware::broadcastradio::V1_1::ProgramListResult;
-
+using ::android::hardware::hidl_vec;
 
 // The main test class for Broadcast Radio HIDL HAL.
 
@@ -56,14 +56,15 @@
  protected:
     virtual void SetUp() override {
         auto factory = ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>();
-        if (factory != 0) {
-            factory->connectModule(Class::AM_FM,
-                             [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
-                if (retval == Result::OK) {
-                  mRadio = IBroadcastRadio::castFrom(result);
-                }
-            });
-        }
+        ASSERT_NE(nullptr, factory.get());
+        Result halResult;
+        factory->connectModule(Class::AM_FM, [&](Result retval, const sp<IBroadcastRadio>& result) {
+            halResult = retval;
+            if (retval == Result::OK) {
+                mRadio = IBroadcastRadio::castFrom(result);
+            }
+        });
+        ASSERT_EQ(Result::OK, halResult);
         mTunerCallback = new MyCallback(this);
         ASSERT_NE(nullptr, mRadio.get());
         ASSERT_NE(nullptr, mTunerCallback.get());
@@ -133,7 +134,9 @@
             return Void();
         }
 
-        virtual Return<void> backgroundScanComplete(ProgramListResult result __unused) {
+        virtual Return<void> backgroundScanComplete(ProgramListResult result) {
+            ALOGV("%s", __func__);
+            mParentTest->onProgramListResultCallback(result);
             return Void();
         }
 
@@ -176,6 +179,15 @@
     }
 
     /**
+     * Method called by MyCallback when a callback with status is received
+     */
+    void onProgramListResultCallback(ProgramListResult result) {
+        Mutex::Autolock _l(mLock);
+        mProgramListResultCallbackData = result;
+        onCallback_l();
+    }
+
+    /**
      * Method called by MyCallback when a boolean indication is received
      */
     void onBoolCallback(bool result) {
@@ -220,6 +232,7 @@
 
     static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
     static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
+    static const nsecs_t kFullScanTimeoutNs = seconds_to_nanoseconds(60);
 
     sp<IBroadcastRadio> mRadio;
     Properties mHalProperties;
@@ -230,6 +243,7 @@
     bool mCallbackCalled;
     bool mBoolCallbackData;
     Result mResultCallbackData;
+    ProgramListResult mProgramListResultCallbackData;
     bool mHwFailure;
 };
 
@@ -277,6 +291,7 @@
                 });
         EXPECT_TRUE(hidlReturn.isOk());
         EXPECT_EQ(Result::OK, halResult);
+        EXPECT_NE(nullptr, mTuner.get());
         EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
     }
     EXPECT_NE(nullptr, mTuner.get());
@@ -454,11 +469,8 @@
     EXPECT_EQ(Result::OK, halResult);
     auto &halInfo_1_1 = halInfo.base;
     if (mResultCallbackData == Result::OK) {
-        EXPECT_TRUE(halInfo_1_1.tuned);
         EXPECT_LE(halInfo_1_1.channel, upperLimit);
         EXPECT_GE(halInfo_1_1.channel, lowerLimit);
-    } else {
-        EXPECT_EQ(false, halInfo_1_1.tuned);
     }
 
     // test cancel
@@ -468,6 +480,53 @@
     EXPECT_EQ(Result::OK, hidlResult);
 }
 
+TEST_F(BroadcastRadioHidlTest, TuneFromProgramList) {
+    ASSERT_TRUE(openTuner());
+    ASSERT_TRUE(checkAntenna());
+
+    ProgramInfo firstProgram;
+    bool isListEmpty;
+    ProgramListResult getListResult = ProgramListResult::NOT_INITIALIZED;
+    auto getListCb = [&](ProgramListResult result, const hidl_vec<ProgramInfo>& list) {
+        getListResult = result;
+        if (result != ProgramListResult::OK) return;
+        isListEmpty = (list.size() == 0);
+        // don't copy the whole list out, it might be heavy
+        if (!isListEmpty) firstProgram = list[0];
+    };
+
+    // first try...
+    auto hidlReturn = mTuner->getProgramList("", getListCb);
+    ASSERT_TRUE(hidlReturn.isOk());
+
+    if (getListResult == ProgramListResult::NOT_STARTED) {
+        auto result = mTuner->startBackgroundScan();
+        ASSERT_TRUE(result.isOk());
+        ASSERT_EQ(ProgramListResult::OK, result);
+        getListResult = ProgramListResult::NOT_READY;  // continue as in NOT_READY case
+    }
+    if (getListResult == ProgramListResult::NOT_READY) {
+        ASSERT_TRUE(waitForCallback(kFullScanTimeoutNs));
+        ASSERT_EQ(ProgramListResult::OK, mProgramListResultCallbackData);
+
+        // second (last) try...
+        hidlReturn = mTuner->getProgramList("", getListCb);
+        ASSERT_TRUE(hidlReturn.isOk());
+        ASSERT_EQ(ProgramListResult::OK, getListResult);
+    }
+
+    if (isListEmpty) {
+        std::cout << "[  SKIPPED ] Program list is empty. " << std::endl;
+        return;
+    }
+
+    auto tuneResult = mTuner->tune_1_1(firstProgram.selector);
+    ASSERT_TRUE(tuneResult.isOk());
+    EXPECT_EQ(Result::OK, tuneResult);
+    EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
+    // TODO(b/36864490): check this too, when mProgramInfoCallbackData is cherry-picked from 1.0
+    // EXPECT_EQ(firstProgram.selector.primaryId, mProgramInfoCallbackData.selector.primaryId);
+}
 
 int main(int argc, char** argv) {
   ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment);
diff --git a/broadcastradio/Android.bp b/broadcastradio/Android.bp
index 7a315fa..a5ad5e7 100644
--- a/broadcastradio/Android.bp
+++ b/broadcastradio/Android.bp
@@ -5,5 +5,7 @@
     "1.0/vts/functional",
     "1.1",
     "1.1/default",
+    "1.1/tests",
+    "1.1/utils",
     "1.1/vts/functional",
 ]
diff --git a/camera/common/1.0/default/CameraParameters.cpp b/camera/common/1.0/default/CameraParameters.cpp
index d224483..e707b08 100644
--- a/camera/common/1.0/default/CameraParameters.cpp
+++ b/camera/common/1.0/default/CameraParameters.cpp
@@ -20,6 +20,7 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include "CameraParameters.h"
 #include <system/graphics.h>
 
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 13c53ba..2ae4853 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -27,6 +27,7 @@
 #include <android/hardware/camera/device/1.0/ICameraDevice.h>
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
 #include <binder/MemoryHeapBase.h>
 #include <CameraMetadata.h>
 #include <CameraParameters.h>
@@ -97,8 +98,10 @@
 using ::android::hardware::MessageQueue;
 using ::android::hardware::kSynchronizedReadWrite;
 using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+using ::android::hidl::manager::V1_0::IServiceManager;
 
-const char kCameraLegacyServiceName[] = "legacy/0";
+const char kCameraPassthroughServiceName[] = "legacy/0";
+const char *kProviderFQName = "android.hardware.camera.provider@2.4::ICameraProvider";
 const uint32_t kMaxPreviewWidth = 1920;
 const uint32_t kMaxPreviewHeight = 1080;
 const uint32_t kMaxVideoWidth = 4096;
@@ -122,21 +125,25 @@
 
 namespace {
     // "device@<version>/legacy/<id>"
-    const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/legacy/(.+)";
+    const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
     const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
     const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
     const char *kHAL3_2 = "3.2";
     const char *kHAL1_0 = "1.0";
 
-    bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm) {
-        std::regex e(kDeviceNameRE);
+    bool matchDeviceName(const hidl_string& deviceName,
+            const hidl_string &providerType, std::smatch& sm) {
+        ::android::String8 pattern;
+        pattern.appendFormat(kDeviceNameRE, providerType.c_str());
+        std::regex e(pattern.string());
         std::string deviceNameStd(deviceName.c_str());
         return std::regex_match(deviceNameStd, sm, e);
     }
 
-    int getCameraDeviceVersion(const hidl_string& deviceName) {
+    int getCameraDeviceVersion(const hidl_string& deviceName,
+            const hidl_string &providerType) {
         std::smatch sm;
-        bool match = matchDeviceName(deviceName, sm);
+        bool match = matchDeviceName(deviceName, providerType, sm);
         if (!match) {
             return -1;
         }
@@ -150,6 +157,45 @@
         return 0;
     }
 
+    bool parseProviderName(const std::string& name, std::string *type /*out*/,
+            uint32_t *id /*out*/) {
+        if (!type || !id) {
+            ADD_FAILURE();
+            return false;
+        }
+
+        std::string::size_type slashIdx = name.find('/');
+        if (slashIdx == std::string::npos || slashIdx == name.size() - 1) {
+            ADD_FAILURE() << "Provider name does not have / separator between type"
+                    "and id";
+            return false;
+        }
+
+        std::string typeVal = name.substr(0, slashIdx);
+
+        char *endPtr;
+        errno = 0;
+        long idVal = strtol(name.c_str() + slashIdx + 1, &endPtr, 10);
+        if (errno != 0) {
+            ADD_FAILURE() << "cannot parse provider id as an integer:" <<
+                    name.c_str() << strerror(errno) << errno;
+            return false;
+        }
+        if (endPtr != name.c_str() + name.size()) {
+            ADD_FAILURE() << "provider id has unexpected length " << name.c_str();
+            return false;
+        }
+        if (idVal < 0) {
+            ADD_FAILURE() << "id is negative: " << name.c_str() << idVal;
+            return false;
+        }
+
+        *type = typeVal;
+        *id = static_cast<uint32_t>(idVal);
+
+        return true;
+    }
+
     Status mapToStatus(::android::status_t s)  {
         switch(s) {
             case ::android::OK:
@@ -184,7 +230,7 @@
     virtual void SetUp() override;
     virtual void TearDown() override;
 
-    sp<ICameraProvider> mProvider;
+    std::unordered_map<std::string, sp<ICameraProvider> > mProviders;
 
 private:
     CameraHidlEnvironment() {}
@@ -193,9 +239,40 @@
 };
 
 void CameraHidlEnvironment::SetUp() {
-    mProvider = ::testing::VtsHalHidlTargetTestBase::getService<ICameraProvider>(kCameraLegacyServiceName);
-    ALOGI_IF(mProvider, "provider is not nullptr, %p", mProvider.get());
-    ASSERT_NE(mProvider, nullptr);
+    sp<IServiceManager> manager = IServiceManager::getService();
+    ASSERT_NE(manager, nullptr);
+
+    manager->listByInterface(kProviderFQName,
+                             [this](const hidl_vec<hidl_string> &registered) {
+        std::string name;
+        uint32_t id;
+        sp<ICameraProvider> provider = nullptr;
+        for (size_t i = 0; i < registered.size(); i++) {
+            ASSERT_TRUE(parseProviderName(registered[i],
+                    &name /*out*/, &id /*out*/));
+            provider = ICameraProvider::tryGetService(registered[i]);
+            ALOGI_IF(provider, "provider is not nullptr, %p", provider.get());
+            if (nullptr != provider.get()) {
+                mProviders.emplace(name, provider);
+            }
+        }
+    });
+
+    std::string legacyName;
+    uint32_t legacyId;
+    ASSERT_TRUE(parseProviderName(kCameraPassthroughServiceName,
+            &legacyName /*out*/, &legacyId /*out*/));
+    auto legacyIt = mProviders.find(legacyName);
+    //Add any legacy passthrough implementations
+    if (legacyIt == mProviders.end()) {
+        sp<ICameraProvider> provider = ICameraProvider::tryGetService(
+                kCameraPassthroughServiceName);
+        if (nullptr != provider.get()) {
+            mProviders.emplace(legacyName, provider);
+        }
+    }
+
+    ASSERT_FALSE(mProviders.empty());
 }
 
 void CameraHidlEnvironment::TearDown() {
@@ -447,7 +524,7 @@
     virtual void SetUp() override {}
     virtual void TearDown() override {}
 
-    hidl_vec<hidl_string> getCameraDeviceNames();
+    hidl_vec<hidl_string> getCameraDeviceNames(sp<ICameraProvider> provider);
 
     struct EmptyDeviceCb : public ICameraDeviceCallback {
         virtual Return<void> processCaptureResult(const hidl_vec<CaptureResult>& /*results*/) override {
@@ -523,7 +600,7 @@
         CameraHidlTest *mParent;               // Parent object
     };
 
-    void openCameraDevice(const std::string &name,const CameraHidlEnvironment* env,
+    void openCameraDevice(const std::string &name, sp<ICameraProvider> provider,
             sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device /*out*/);
     void setupPreviewWindow(
             const sp<::android::hardware::camera::device::V1_0::ICameraDevice> &device,
@@ -546,11 +623,11 @@
     void waitForFrameLocked(DataCallbackMsg msgFrame,
             std::unique_lock<std::mutex> &l);
     void openEmptyDeviceSession(const std::string &name,
-            const CameraHidlEnvironment* env,
+            sp<ICameraProvider> provider,
             sp<ICameraDeviceSession> *session /*out*/,
             camera_metadata_t **staticMeta /*out*/);
     void configurePreviewStream(const std::string &name,
-            const CameraHidlEnvironment* env,
+            sp<ICameraProvider> provider,
             const AvailableStream *previewThreshold,
             sp<ICameraDeviceSession> *session /*out*/,
             Stream *previewStream /*out*/,
@@ -934,11 +1011,10 @@
     return Void();
 }
 
-hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames() {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames(sp<ICameraProvider> provider) {
     hidl_vec<hidl_string> cameraDeviceNames;
     Return<void> ret;
-    ret = env->mProvider->getCameraIdList(
+    ret = provider->getCameraIdList(
         [&](auto status, const auto& idList) {
             ALOGI("getCameraIdList returns status:%d", (int)status);
             for (size_t i = 0; i < idList.size(); i++) {
@@ -956,58 +1032,63 @@
 // Test if ICameraProvider::isTorchModeSupported returns Status::OK
 TEST_F(CameraHidlTest, isTorchModeSupported) {
     Return<void> ret;
-    ret = CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
-        [&](auto status, bool support) {
-            ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
-                    (int)status, support);
-            ASSERT_EQ(Status::OK, status);
-        });
-    ASSERT_TRUE(ret.isOk());
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        ret = provider.second->isSetTorchModeSupported(
+            [&](auto status, bool support) {
+                ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
+                        (int)status, support);
+                ASSERT_EQ(Status::OK, status);
+            });
+        ASSERT_TRUE(ret.isOk());
+    }
 }
 
 // TODO: consider removing this test if getCameraDeviceNames() has the same coverage
 TEST_F(CameraHidlTest, getCameraIdList) {
     Return<void> ret;
-    ret = CameraHidlEnvironment::Instance()->mProvider->getCameraIdList(
-        [&](auto status, const auto& idList) {
-            ALOGI("getCameraIdList returns status:%d", (int)status);
-            for (size_t i = 0; i < idList.size(); i++) {
-                ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
-            }
-            ASSERT_EQ(Status::OK, status);
-            // This is true for internal camera provider.
-            // Not necessary hold for external cameras providers
-            ASSERT_GT(idList.size(), 0u);
-        });
-    ASSERT_TRUE(ret.isOk());
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        ret = provider.second->getCameraIdList(
+            [&](auto status, const auto& idList) {
+                ALOGI("getCameraIdList returns status:%d", (int)status);
+                for (size_t i = 0; i < idList.size(); i++) {
+                    ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
+                }
+                ASSERT_EQ(Status::OK, status);
+                // This is true for internal camera provider.
+                // Not necessary hold for external cameras providers
+                ASSERT_GT(idList.size(), 0u);
+            });
+        ASSERT_TRUE(ret.isOk());
+    }
 }
 
 // Test if ICameraProvider::getVendorTags returns Status::OK
 TEST_F(CameraHidlTest, getVendorTags) {
     Return<void> ret;
-    ret = CameraHidlEnvironment::Instance()->mProvider->getVendorTags(
-        [&](auto status, const auto& vendorTagSecs) {
-            ALOGI("getVendorTags returns status:%d numSections %zu",
-                    (int)status, vendorTagSecs.size());
-            for (size_t i = 0; i < vendorTagSecs.size(); i++) {
-                ALOGI("Vendor tag section %zu name %s",
-                        i, vendorTagSecs[i].sectionName.c_str());
-                for (size_t j = 0; j < vendorTagSecs[i].tags.size(); j++) {
-                    const auto& tag = vendorTagSecs[i].tags[j];
-                    ALOGI("Vendor tag id %u name %s type %d",
-                            tag.tagId,
-                            tag.tagName.c_str(),
-                            (int) tag.tagType);
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        ret = provider.second->getVendorTags(
+            [&](auto status, const auto& vendorTagSecs) {
+                ALOGI("getVendorTags returns status:%d numSections %zu",
+                        (int)status, vendorTagSecs.size());
+                for (size_t i = 0; i < vendorTagSecs.size(); i++) {
+                    ALOGI("Vendor tag section %zu name %s",
+                            i, vendorTagSecs[i].sectionName.c_str());
+                    for (size_t j = 0; j < vendorTagSecs[i].tags.size(); j++) {
+                        const auto& tag = vendorTagSecs[i].tags[j];
+                        ALOGI("Vendor tag id %u name %s type %d",
+                                tag.tagId,
+                                tag.tagName.c_str(),
+                                (int) tag.tagType);
+                    }
                 }
-            }
-            ASSERT_EQ(Status::OK, status);
-        });
-    ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(Status::OK, status);
+            });
+        ASSERT_TRUE(ret.isOk());
+    }
 }
 
 // Test if ICameraProvider::setCallback returns Status::OK
 TEST_F(CameraHidlTest, setCallback) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
     struct ProviderCb : public ICameraProviderCallback {
         virtual Return<void> cameraDeviceStatusChange(
                 const hidl_string& cameraDeviceName,
@@ -1026,37 +1107,45 @@
         }
     };
     sp<ProviderCb> cb = new ProviderCb;
-    auto status = env->mProvider->setCallback(cb);
-    ASSERT_TRUE(status.isOk());
-    ASSERT_EQ(Status::OK, status);
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        auto status = provider.second->setCallback(cb);
+        ASSERT_TRUE(status.isOk());
+        ASSERT_EQ(Status::OK, status);
+    }
 }
 
 // Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
 TEST_F(CameraHidlTest, getCameraDeviceInterface) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            Return<void> ret;
-            ret = env->mProvider->getCameraDeviceInterface_V3_x(
-                name,
-                [&](auto status, const auto& device3_2) {
-                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device3_2, nullptr);
-                });
-            ASSERT_TRUE(ret.isOk());
-        } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            Return<void> ret;
-            ret = env->mProvider->getCameraDeviceInterface_V1_x(
-                name,
-                [&](auto status, const auto& device1) {
-                    ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device1, nullptr);
-                });
-            ASSERT_TRUE(ret.isOk());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                Return<void> ret;
+                ret = provider.second->getCameraDeviceInterface_V3_x(
+                    name,
+                    [&](auto status, const auto& device3_2) {
+                        ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device3_2, nullptr);
+                    });
+                ASSERT_TRUE(ret.isOk());
+            } else if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                Return<void> ret;
+                ret = provider.second->getCameraDeviceInterface_V1_x(
+                    name,
+                    [&](auto status, const auto& device1) {
+                        ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device1, nullptr);
+                    });
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
@@ -1064,60 +1153,66 @@
 // Verify that the device resource cost can be retrieved and the values are
 // sane.
 TEST_F(CameraHidlTest, getResourceCost) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
-            ALOGI("getResourceCost: Testing camera device %s", name.c_str());
-            Return<void> ret;
-            ret = env->mProvider->getCameraDeviceInterface_V3_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device3_2 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+                ALOGI("getResourceCost: Testing camera device %s", name.c_str());
+                Return<void> ret;
+                ret = provider.second->getCameraDeviceInterface_V3_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device3_2 = device;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            ret = device3_2->getResourceCost(
-                [&](auto status, const auto& resourceCost) {
-                    ALOGI("getResourceCost returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ALOGI("    Resource cost is %d", resourceCost.resourceCost);
-                    ASSERT_LE(resourceCost.resourceCost, 100u);
-                    for (const auto& name : resourceCost.conflictingDevices) {
-                        ALOGI("    Conflicting device: %s", name.c_str());
-                    }
-                });
-            ASSERT_TRUE(ret.isOk());
-        } else {
-            ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            ALOGI("getResourceCost: Testing camera device %s", name.c_str());
-            Return<void> ret;
-            ret = env->mProvider->getCameraDeviceInterface_V1_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device1 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
+                ret = device3_2->getResourceCost(
+                    [&](auto status, const auto& resourceCost) {
+                        ALOGI("getResourceCost returns status:%d", (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ALOGI("    Resource cost is %d", resourceCost.resourceCost);
+                        ASSERT_LE(resourceCost.resourceCost, 100u);
+                        for (const auto& name : resourceCost.conflictingDevices) {
+                            ALOGI("    Conflicting device: %s", name.c_str());
+                        }
+                    });
+                ASSERT_TRUE(ret.isOk());
+            } else {
+                ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                ALOGI("getResourceCost: Testing camera device %s", name.c_str());
+                Return<void> ret;
+                ret = provider.second->getCameraDeviceInterface_V1_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device1 = device;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            ret = device1->getResourceCost(
-                [&](auto status, const auto& resourceCost) {
-                    ALOGI("getResourceCost returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ALOGI("    Resource cost is %d", resourceCost.resourceCost);
-                    ASSERT_LE(resourceCost.resourceCost, 100u);
-                    for (const auto& name : resourceCost.conflictingDevices) {
-                        ALOGI("    Conflicting device: %s", name.c_str());
-                    }
-                });
-            ASSERT_TRUE(ret.isOk());
+                ret = device1->getResourceCost(
+                    [&](auto status, const auto& resourceCost) {
+                        ALOGI("getResourceCost returns status:%d", (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ALOGI("    Resource cost is %d",
+                              resourceCost.resourceCost);
+                        ASSERT_LE(resourceCost.resourceCost, 100u);
+                        for (const auto& name : resourceCost.conflictingDevices) {
+                            ALOGI("    Conflicting device: %s", name.c_str());
+                        }
+                    });
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
@@ -1125,126 +1220,143 @@
 // Verify that the static camera info can be retrieved
 // successfully.
 TEST_F(CameraHidlTest, getCameraInfo) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
-            Return<void> ret;
-            ret = env->mProvider->getCameraDeviceInterface_V1_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device1 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                ALOGI("getCameraCharacteristics: Testing camera device %s",
+                      name.c_str());
+                Return<void> ret;
+                ret = provider.second->getCameraDeviceInterface_V1_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device1 = device;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            ret = device1->getCameraInfo(
-                [&](auto status, const auto& info) {
-                    ALOGI("getCameraInfo returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    switch(info.orientation) {
-                        case 0:
-                        case 90:
-                        case 180:
-                        case 270:
-                            //Expected cases
-                            ALOGI("camera orientation: %d", info.orientation);
-                            break;
-                        default:
-                            FAIL() << "Unexpected camera orientation:" << info.orientation;
-                    }
-                    switch(info.facing) {
-                        case CameraFacing::BACK:
-                        case CameraFacing::FRONT:
-                        case CameraFacing::EXTERNAL:
-                            //Expected cases
-                            ALOGI("camera facing: %d", info.facing);
-                            break;
-                        default:
-                            FAIL() << "Unexpected camera facing:" << static_cast<uint32_t> (info.facing);
-                    }
-                });
-            ASSERT_TRUE(ret.isOk());
+                ret = device1->getCameraInfo(
+                    [&](auto status, const auto& info) {
+                        ALOGI("getCameraInfo returns status:%d", (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        switch(info.orientation) {
+                            case 0:
+                            case 90:
+                            case 180:
+                            case 270:
+                                //Expected cases
+                                ALOGI("camera orientation: %d", info.orientation);
+                                break;
+                            default:
+                                FAIL() << "Unexpected camera orientation:" << info.orientation;
+                        }
+                        switch(info.facing) {
+                            case CameraFacing::BACK:
+                            case CameraFacing::FRONT:
+                            case CameraFacing::EXTERNAL:
+                                //Expected cases
+                                ALOGI("camera facing: %d", info.facing);
+                                break;
+                            default:
+                                FAIL() << "Unexpected camera facing:" << static_cast<uint32_t> (
+                                        info.facing);
+                        }
+                    });
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
 
 // Check whether preview window can be configured
 TEST_F(CameraHidlTest, setPreviewWindow) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-                    openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1,
-                    &bufferItemConsumer /*out*/, &bufferHandler /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1,
+                        &bufferItemConsumer /*out*/, &bufferHandler /*out*/);
 
-            Return<void> ret;
-            ret = device1->close();
-            ASSERT_TRUE(ret.isOk());
+                Return<void> ret;
+                ret = device1->close();
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
 
 // Verify that setting preview window fails in case device is not open
 TEST_F(CameraHidlTest, setPreviewWindowInvalid) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
-            Return<void> ret;
-            ret = env->mProvider->getCameraDeviceInterface_V1_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device1 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                ALOGI("getCameraCharacteristics: Testing camera device %s",
+                      name.c_str());
+                Return<void> ret;
+                ret = provider.second->getCameraDeviceInterface_V1_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device1 = device;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            Return<Status> returnStatus = device1->setPreviewWindow(nullptr);
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OPERATION_NOT_SUPPORTED, returnStatus);
+                Return<Status> returnStatus = device1->setPreviewWindow(nullptr);
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OPERATION_NOT_SUPPORTED, returnStatus);
+            }
         }
     }
 }
 
 // Start and stop preview checking whether it gets enabled in between.
 TEST_F(CameraHidlTest, startStopPreview) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-                    openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1,
-                    &bufferItemConsumer /*out*/, &bufferHandler /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1,
+                        &bufferItemConsumer /*out*/, &bufferHandler /*out*/);
 
-            startPreview(device1);
+                startPreview(device1);
 
-            Return<bool> returnBoolStatus = device1->previewEnabled();
-            ASSERT_TRUE(returnBoolStatus.isOk());
-            ASSERT_TRUE(returnBoolStatus);
+                Return<bool> returnBoolStatus = device1->previewEnabled();
+                ASSERT_TRUE(returnBoolStatus.isOk());
+                ASSERT_TRUE(returnBoolStatus);
 
-            stopPreviewAndClose(device1);
+                stopPreviewAndClose(device1);
+            }
         }
     }
 }
@@ -1252,599 +1364,646 @@
 // Start preview without active preview window. Preview should start as soon
 // as a valid active window gets configured.
 TEST_F(CameraHidlTest, startStopPreviewDelayed) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
 
-            Return<Status> returnStatus = device1->setPreviewWindow(nullptr);
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
+                Return<Status> returnStatus = device1->setPreviewWindow(nullptr);
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
 
-            startPreview(device1);
+                startPreview(device1);
 
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
-                    &bufferHandler /*out*/);
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+                        &bufferHandler /*out*/);
 
-            //Preview should get enabled now
-            Return<bool> returnBoolStatus = device1->previewEnabled();
-            ASSERT_TRUE(returnBoolStatus.isOk());
-            ASSERT_TRUE(returnBoolStatus);
+                //Preview should get enabled now
+                Return<bool> returnBoolStatus = device1->previewEnabled();
+                ASSERT_TRUE(returnBoolStatus.isOk());
+                ASSERT_TRUE(returnBoolStatus);
 
-            stopPreviewAndClose(device1);
+                stopPreviewAndClose(device1);
+            }
         }
     }
 }
 
 // Verify that image capture behaves as expected along with preview callbacks.
 TEST_F(CameraHidlTest, takePicture) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
-                    &bufferHandler /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+                        &bufferHandler /*out*/);
 
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+                }
+
+                enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME,
+                              device1);
+                startPreview(device1);
+
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l);
+                }
+
+                disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME,
+                                device1);
+                enableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE,
+                        device1);
+
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+                }
+
+                Return<Status> returnStatus = device1->takePicture();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
+
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    waitForFrameLocked(DataCallbackMsg::COMPRESSED_IMAGE, l);
+                }
+
+                disableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE,
+                        device1);
+                stopPreviewAndClose(device1);
             }
-
-            enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
-            startPreview(device1);
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l);
-            }
-
-            disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME,
-                            device1);
-            enableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE,
-                    device1);
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
-            }
-
-            Return<Status> returnStatus = device1->takePicture();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                waitForFrameLocked(DataCallbackMsg::COMPRESSED_IMAGE, l);
-            }
-
-            disableMsgType((unsigned int)DataCallbackMsg::COMPRESSED_IMAGE,
-                    device1);
-            stopPreviewAndClose(device1);
         }
     }
 }
 
 // Image capture should fail in case preview didn't get enabled first.
 TEST_F(CameraHidlTest, takePictureFail) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
 
-            Return<Status> returnStatus = device1->takePicture();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_NE(Status::OK, returnStatus);
+                Return<Status> returnStatus = device1->takePicture();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_NE(Status::OK, returnStatus);
 
-            Return<void> ret = device1->close();
-            ASSERT_TRUE(ret.isOk());
+                Return<void> ret = device1->close();
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
 
 // Verify that image capture can be cancelled.
 TEST_F(CameraHidlTest, cancelPicture) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
-                    &bufferHandler /*out*/);
-            startPreview(device1);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+                        &bufferHandler /*out*/);
+                startPreview(device1);
 
-            Return<Status> returnStatus = device1->takePicture();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
+                Return<Status> returnStatus = device1->takePicture();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
 
-            returnStatus = device1->cancelPicture();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
+                returnStatus = device1->cancelPicture();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
 
-            stopPreviewAndClose(device1);
+                stopPreviewAndClose(device1);
+            }
         }
     }
 }
 
 // Image capture cancel should fail when image capture is not running.
 TEST_F(CameraHidlTest, cancelPictureFail) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
-                    &bufferHandler /*out*/);
-            startPreview(device1);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+                        &bufferHandler /*out*/);
+                startPreview(device1);
 
-            Return<Status> returnStatus = device1->cancelPicture();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_NE(Status::OK, returnStatus);
+                Return<Status> returnStatus = device1->cancelPicture();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_NE(Status::OK, returnStatus);
 
-            stopPreviewAndClose(device1);
+                stopPreviewAndClose(device1);
+            }
         }
     }
 }
 
 // Test basic video recording.
 TEST_F(CameraHidlTest, startStopRecording) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
-                    &bufferHandler /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+                        &bufferHandler /*out*/);
 
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
-            }
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+                }
 
-            enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
-            startPreview(device1);
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l);
-                mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
-                mVideoBufferIndex = UINT32_MAX;
-            }
-
-            disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME, device1);
-
-            bool videoMetaEnabled = false;
-            Return<Status> returnStatus = device1->storeMetaDataInBuffers(true);
-            ASSERT_TRUE(returnStatus.isOk());
-            // It is allowed for devices to not support this feature
-            ASSERT_TRUE((Status::OK == returnStatus) ||
-                    (Status::OPERATION_NOT_SUPPORTED == returnStatus));
-            if (Status::OK == returnStatus) {
-                videoMetaEnabled = true;
-            }
-
-            enableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME, device1);
-            Return<bool> returnBoolStatus = device1->recordingEnabled();
-            ASSERT_TRUE(returnBoolStatus.isOk());
-            ASSERT_FALSE(returnBoolStatus);
-
-            returnStatus = device1->startRecording();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                waitForFrameLocked(DataCallbackMsg::VIDEO_FRAME, l);
-                ASSERT_NE(UINT32_MAX, mVideoBufferIndex);
-                disableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME,
+                enableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME,
                         device1);
-            }
+                startPreview(device1);
 
-            returnBoolStatus = device1->recordingEnabled();
-            ASSERT_TRUE(returnBoolStatus.isOk());
-            ASSERT_TRUE(returnBoolStatus);
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    waitForFrameLocked(DataCallbackMsg::PREVIEW_FRAME, l);
+                    mDataMessageTypeReceived = DataCallbackMsg::RAW_IMAGE_NOTIFY;
+                    mVideoBufferIndex = UINT32_MAX;
+                }
 
-            Return<void> ret;
-            if (videoMetaEnabled) {
-                ret = device1->releaseRecordingFrameHandle(mVideoData,
-                        mVideoBufferIndex, mVideoNativeHandle);
+                disableMsgType((unsigned int)DataCallbackMsg::PREVIEW_FRAME,
+                        device1);
+
+                bool videoMetaEnabled = false;
+                Return<Status> returnStatus = device1->storeMetaDataInBuffers(
+                        true);
+                ASSERT_TRUE(returnStatus.isOk());
+                // It is allowed for devices to not support this feature
+                ASSERT_TRUE((Status::OK == returnStatus) ||
+                        (Status::OPERATION_NOT_SUPPORTED == returnStatus));
+                if (Status::OK == returnStatus) {
+                    videoMetaEnabled = true;
+                }
+
+                enableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME,
+                        device1);
+                Return<bool> returnBoolStatus = device1->recordingEnabled();
+                ASSERT_TRUE(returnBoolStatus.isOk());
+                ASSERT_FALSE(returnBoolStatus);
+
+                returnStatus = device1->startRecording();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
+
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    waitForFrameLocked(DataCallbackMsg::VIDEO_FRAME, l);
+                    ASSERT_NE(UINT32_MAX, mVideoBufferIndex);
+                    disableMsgType((unsigned int)DataCallbackMsg::VIDEO_FRAME,
+                            device1);
+                }
+
+                returnBoolStatus = device1->recordingEnabled();
+                ASSERT_TRUE(returnBoolStatus.isOk());
+                ASSERT_TRUE(returnBoolStatus);
+
+                Return<void> ret;
+                if (videoMetaEnabled) {
+                    ret = device1->releaseRecordingFrameHandle(mVideoData,
+                            mVideoBufferIndex, mVideoNativeHandle);
+                    ASSERT_TRUE(ret.isOk());
+                } else {
+                    ret = device1->releaseRecordingFrame(mVideoData,
+                            mVideoBufferIndex);
+                    ASSERT_TRUE(ret.isOk());
+                }
+
+                ret = device1->stopRecording();
                 ASSERT_TRUE(ret.isOk());
-            } else {
-                ret = device1->releaseRecordingFrame(mVideoData, mVideoBufferIndex);
-                ASSERT_TRUE(ret.isOk());
+
+                stopPreviewAndClose(device1);
             }
-
-            ret = device1->stopRecording();
-            ASSERT_TRUE(ret.isOk());
-
-            stopPreviewAndClose(device1);
         }
     }
 }
 
 // It shouldn't be possible to start recording without enabling preview first.
 TEST_F(CameraHidlTest, startRecordingFail) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
 
-            Return<bool> returnBoolStatus = device1->recordingEnabled();
-            ASSERT_TRUE(returnBoolStatus.isOk());
-            ASSERT_FALSE(returnBoolStatus);
+                Return<bool> returnBoolStatus = device1->recordingEnabled();
+                ASSERT_TRUE(returnBoolStatus.isOk());
+                ASSERT_FALSE(returnBoolStatus);
 
-            Return<Status> returnStatus = device1->startRecording();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_NE(Status::OK, returnStatus);
+                Return<Status> returnStatus = device1->startRecording();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_NE(Status::OK, returnStatus);
 
-            Return<void> ret = device1->close();
-            ASSERT_TRUE(ret.isOk());
+                Return<void> ret = device1->close();
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
 
 // Check autofocus support if available.
 TEST_F(CameraHidlTest, autoFocus) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    std::vector<const char *> focusModes = {CameraParameters::FOCUS_MODE_AUTO,
-            CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE,
-            CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO};
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        std::vector<const char *> focusModes = {CameraParameters::FOCUS_MODE_AUTO,
+                CameraParameters::FOCUS_MODE_CONTINUOUS_PICTURE,
+                CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO};
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
 
-            CameraParameters cameraParams;
-            getParameters(device1, &cameraParams /*out*/);
+                CameraParameters cameraParams;
+                getParameters(device1, &cameraParams /*out*/);
 
-            if (Status::OK != isAutoFocusModeAvailable(cameraParams,
-                    CameraParameters::FOCUS_MODE_AUTO)) {
-                Return<void> ret = device1->close();
-                ASSERT_TRUE(ret.isOk());
-                continue;
-            }
-
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
-                    &bufferHandler /*out*/);
-            startPreview(device1);
-            enableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1);
-
-            for (auto &iter : focusModes) {
                 if (Status::OK != isAutoFocusModeAvailable(cameraParams,
-                        iter)) {
+                        CameraParameters::FOCUS_MODE_AUTO)) {
+                    Return<void> ret = device1->close();
+                    ASSERT_TRUE(ret.isOk());
                     continue;
                 }
 
-                cameraParams.set(CameraParameters::KEY_FOCUS_MODE, iter);
-                setParameters(device1, cameraParams);
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    mNotifyMessage = NotifyCallbackMsg::ERROR;
-                }
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+                        &bufferHandler /*out*/);
+                startPreview(device1);
+                enableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1);
 
-                Return<Status> returnStatus = device1->autoFocus();
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, returnStatus);
+                for (auto &iter : focusModes) {
+                    if (Status::OK != isAutoFocusModeAvailable(cameraParams,
+                            iter)) {
+                        continue;
+                    }
 
-                {
-                    std::unique_lock<std::mutex> l(mLock);
-                    while (NotifyCallbackMsg::FOCUS != mNotifyMessage) {
-                        auto timeout = std::chrono::system_clock::now() +
-                                std::chrono::seconds(kAutoFocusTimeoutSec);
-                        ASSERT_NE(std::cv_status::timeout,
-                                mResultCondition.wait_until(l, timeout));
+                    cameraParams.set(CameraParameters::KEY_FOCUS_MODE, iter);
+                    setParameters(device1, cameraParams);
+                    {
+                        std::unique_lock<std::mutex> l(mLock);
+                        mNotifyMessage = NotifyCallbackMsg::ERROR;
+                    }
+
+                    Return<Status> returnStatus = device1->autoFocus();
+                    ASSERT_TRUE(returnStatus.isOk());
+                    ASSERT_EQ(Status::OK, returnStatus);
+
+                    {
+                        std::unique_lock<std::mutex> l(mLock);
+                        while (NotifyCallbackMsg::FOCUS != mNotifyMessage) {
+                            auto timeout = std::chrono::system_clock::now() +
+                                    std::chrono::seconds(kAutoFocusTimeoutSec);
+                            ASSERT_NE(std::cv_status::timeout,
+                                    mResultCondition.wait_until(l, timeout));
+                        }
                     }
                 }
-            }
 
-            disableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1);
-            stopPreviewAndClose(device1);
+                disableMsgType((unsigned int)NotifyCallbackMsg::FOCUS, device1);
+                stopPreviewAndClose(device1);
+            }
         }
     }
 }
 
 // In case autofocus is supported verify that it can be cancelled.
 TEST_F(CameraHidlTest, cancelAutoFocus) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
 
-            CameraParameters cameraParams;
-            getParameters(device1, &cameraParams /*out*/);
+                CameraParameters cameraParams;
+                getParameters(device1, &cameraParams /*out*/);
 
-            if (Status::OK != isAutoFocusModeAvailable(cameraParams,
-                    CameraParameters::FOCUS_MODE_AUTO)) {
-                Return<void> ret = device1->close();
-                ASSERT_TRUE(ret.isOk());
-                continue;
+                if (Status::OK != isAutoFocusModeAvailable(cameraParams,
+                        CameraParameters::FOCUS_MODE_AUTO)) {
+                    Return<void> ret = device1->close();
+                    ASSERT_TRUE(ret.isOk());
+                    continue;
+                }
+
+                // It should be fine to call before preview starts.
+                ASSERT_EQ(Status::OK, device1->cancelAutoFocus());
+
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+                        &bufferHandler /*out*/);
+                startPreview(device1);
+
+                // It should be fine to call after preview starts too.
+                Return<Status> returnStatus = device1->cancelAutoFocus();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
+
+                returnStatus = device1->autoFocus();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
+
+                returnStatus = device1->cancelAutoFocus();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
+
+                stopPreviewAndClose(device1);
             }
-
-            // It should be fine to call before preview starts.
-            ASSERT_EQ(Status::OK, device1->cancelAutoFocus());
-
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
-                    &bufferHandler /*out*/);
-            startPreview(device1);
-
-            // It should be fine to call after preview starts too.
-            Return<Status> returnStatus = device1->cancelAutoFocus();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
-
-            returnStatus = device1->autoFocus();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
-
-            returnStatus = device1->cancelAutoFocus();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
-
-            stopPreviewAndClose(device1);
         }
     }
 }
 
 // Check whether face detection is available and try to enable&disable.
 TEST_F(CameraHidlTest, sendCommandFaceDetection) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
 
-            CameraParameters cameraParams;
-            getParameters(device1, &cameraParams /*out*/);
+                CameraParameters cameraParams;
+                getParameters(device1, &cameraParams /*out*/);
 
-            int32_t hwFaces = cameraParams.getInt(
-                    CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW);
-            int32_t swFaces = cameraParams.getInt(
-                    CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW);
-            if ((0 >= hwFaces) && (0 >= swFaces)) {
-                Return<void> ret = device1->close();
-                ASSERT_TRUE(ret.isOk());
-                continue;
+                int32_t hwFaces = cameraParams.getInt(
+                        CameraParameters::KEY_MAX_NUM_DETECTED_FACES_HW);
+                int32_t swFaces = cameraParams.getInt(
+                        CameraParameters::KEY_MAX_NUM_DETECTED_FACES_SW);
+                if ((0 >= hwFaces) && (0 >= swFaces)) {
+                    Return<void> ret = device1->close();
+                    ASSERT_TRUE(ret.isOk());
+                    continue;
+                }
+
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+                        &bufferHandler /*out*/);
+                startPreview(device1);
+
+                if (0 < hwFaces) {
+                    Return<Status> returnStatus = device1->sendCommand(
+                            CommandType::START_FACE_DETECTION,
+                            CAMERA_FACE_DETECTION_HW, 0);
+                    ASSERT_TRUE(returnStatus.isOk());
+                    ASSERT_EQ(Status::OK, returnStatus);
+                    // TODO(epeev) : Enable and check for face notifications
+                    returnStatus = device1->sendCommand(
+                            CommandType::STOP_FACE_DETECTION,
+                            CAMERA_FACE_DETECTION_HW, 0);
+                    ASSERT_TRUE(returnStatus.isOk());
+                    ASSERT_EQ(Status::OK, returnStatus);
+                }
+
+                if (0 < swFaces) {
+                    Return<Status> returnStatus = device1->sendCommand(
+                            CommandType::START_FACE_DETECTION,
+                            CAMERA_FACE_DETECTION_SW, 0);
+                    ASSERT_TRUE(returnStatus.isOk());
+                    ASSERT_EQ(Status::OK, returnStatus);
+                    // TODO(epeev) : Enable and check for face notifications
+                    returnStatus = device1->sendCommand(
+                            CommandType::STOP_FACE_DETECTION,
+                            CAMERA_FACE_DETECTION_SW, 0);
+                    ASSERT_TRUE(returnStatus.isOk());
+                    ASSERT_EQ(Status::OK, returnStatus);
+                }
+
+                stopPreviewAndClose(device1);
             }
-
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
-                    &bufferHandler /*out*/);
-            startPreview(device1);
-
-            if (0 < hwFaces) {
-                Return<Status> returnStatus = device1->sendCommand(
-                        CommandType::START_FACE_DETECTION,
-                        CAMERA_FACE_DETECTION_HW, 0);
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, returnStatus);
-                // TODO(epeev) : Enable and check for face notifications
-                returnStatus = device1->sendCommand(
-                        CommandType::STOP_FACE_DETECTION,
-                        CAMERA_FACE_DETECTION_HW, 0);
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, returnStatus);
-            }
-
-            if (0 < swFaces) {
-                Return<Status> returnStatus = device1->sendCommand(
-                        CommandType::START_FACE_DETECTION,
-                        CAMERA_FACE_DETECTION_SW, 0);
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, returnStatus);
-                // TODO(epeev) : Enable and check for face notifications
-                returnStatus = device1->sendCommand(
-                        CommandType::STOP_FACE_DETECTION,
-                        CAMERA_FACE_DETECTION_SW, 0);
-                ASSERT_TRUE(returnStatus.isOk());
-                ASSERT_EQ(Status::OK, returnStatus);
-            }
-
-            stopPreviewAndClose(device1);
         }
     }
 }
 
 // Check whether smooth zoom is available and try to enable&disable.
 TEST_F(CameraHidlTest, sendCommandSmoothZoom) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
 
-            CameraParameters cameraParams;
-            getParameters(device1, &cameraParams /*out*/);
+                CameraParameters cameraParams;
+                getParameters(device1, &cameraParams /*out*/);
 
-            const char *smoothZoomStr = cameraParams.get(
-                    CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED);
-            bool smoothZoomSupported = ((nullptr != smoothZoomStr) &&
-                    (strcmp(smoothZoomStr, CameraParameters::TRUE) == 0)) ?
-                            true : false;
-            if (!smoothZoomSupported) {
-                Return<void> ret = device1->close();
-                ASSERT_TRUE(ret.isOk());
-                continue;
+                const char *smoothZoomStr = cameraParams.get(
+                        CameraParameters::KEY_SMOOTH_ZOOM_SUPPORTED);
+                bool smoothZoomSupported = ((nullptr != smoothZoomStr) &&
+                        (strcmp(smoothZoomStr, CameraParameters::TRUE) == 0)) ?
+                                true : false;
+                if (!smoothZoomSupported) {
+                    Return<void> ret = device1->close();
+                    ASSERT_TRUE(ret.isOk());
+                    continue;
+                }
+
+                int32_t maxZoom = cameraParams.getInt(
+                        CameraParameters::KEY_MAX_ZOOM);
+                ASSERT_TRUE(0 < maxZoom);
+
+                sp<BufferItemConsumer> bufferItemConsumer;
+                sp<BufferItemHander> bufferHandler;
+                setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
+                        &bufferHandler /*out*/);
+                startPreview(device1);
+                setParameters(device1, cameraParams);
+
+                Return<Status> returnStatus = device1->sendCommand(
+                        CommandType::START_SMOOTH_ZOOM, maxZoom, 0);
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
+                // TODO(epeev) : Enable and check for face notifications
+                returnStatus = device1->sendCommand(
+                        CommandType::STOP_SMOOTH_ZOOM, 0, 0);
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
+
+                stopPreviewAndClose(device1);
             }
-
-            int32_t maxZoom = cameraParams.getInt(
-                    CameraParameters::KEY_MAX_ZOOM);
-            ASSERT_TRUE(0 < maxZoom);
-
-            sp<BufferItemConsumer> bufferItemConsumer;
-            sp<BufferItemHander> bufferHandler;
-            setupPreviewWindow(device1, &bufferItemConsumer /*out*/,
-                    &bufferHandler /*out*/);
-            startPreview(device1);
-            setParameters(device1, cameraParams);
-
-            Return<Status> returnStatus = device1->sendCommand(
-                    CommandType::START_SMOOTH_ZOOM, maxZoom, 0);
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
-            // TODO(epeev) : Enable and check for face notifications
-            returnStatus = device1->sendCommand(CommandType::STOP_SMOOTH_ZOOM,
-                    0, 0);
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
-
-            stopPreviewAndClose(device1);
         }
     }
 }
 
 // Basic sanity tests related to camera parameters.
 TEST_F(CameraHidlTest, getSetParameters) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
 
-            CameraParameters cameraParams;
-            getParameters(device1, &cameraParams /*out*/);
+                CameraParameters cameraParams;
+                getParameters(device1, &cameraParams /*out*/);
 
-            int32_t width, height;
-            cameraParams.getPictureSize(&width, &height);
-            ASSERT_TRUE((0 < width) && (0 < height));
-            cameraParams.getPreviewSize(&width, &height);
-            ASSERT_TRUE((0 < width) && (0 < height));
-            int32_t minFps, maxFps;
-            cameraParams.getPreviewFpsRange(&minFps, &maxFps);
-            ASSERT_TRUE((0 < minFps) && (0 < maxFps));
-            ASSERT_NE(nullptr, cameraParams.getPreviewFormat());
-            ASSERT_NE(nullptr, cameraParams.getPictureFormat());
-            ASSERT_TRUE(strcmp(CameraParameters::PIXEL_FORMAT_JPEG,
-                    cameraParams.getPictureFormat()) == 0);
+                int32_t width, height;
+                cameraParams.getPictureSize(&width, &height);
+                ASSERT_TRUE((0 < width) && (0 < height));
+                cameraParams.getPreviewSize(&width, &height);
+                ASSERT_TRUE((0 < width) && (0 < height));
+                int32_t minFps, maxFps;
+                cameraParams.getPreviewFpsRange(&minFps, &maxFps);
+                ASSERT_TRUE((0 < minFps) && (0 < maxFps));
+                ASSERT_NE(nullptr, cameraParams.getPreviewFormat());
+                ASSERT_NE(nullptr, cameraParams.getPictureFormat());
+                ASSERT_TRUE(strcmp(CameraParameters::PIXEL_FORMAT_JPEG,
+                        cameraParams.getPictureFormat()) == 0);
 
-            const char *flashMode = cameraParams.get(
-                    CameraParameters::KEY_FLASH_MODE);
-            ASSERT_TRUE((nullptr == flashMode) || (strcmp(
-                    CameraParameters::FLASH_MODE_OFF, flashMode) == 0));
+                const char *flashMode = cameraParams.get(
+                        CameraParameters::KEY_FLASH_MODE);
+                ASSERT_TRUE((nullptr == flashMode) || (strcmp(
+                        CameraParameters::FLASH_MODE_OFF, flashMode) == 0));
 
-            const char *wbMode = cameraParams.get(
-                    CameraParameters::KEY_WHITE_BALANCE);
-            ASSERT_TRUE((nullptr == wbMode) || (strcmp(
-                    CameraParameters::WHITE_BALANCE_AUTO, wbMode) == 0));
+                const char *wbMode = cameraParams.get(
+                        CameraParameters::KEY_WHITE_BALANCE);
+                ASSERT_TRUE((nullptr == wbMode) || (strcmp(
+                        CameraParameters::WHITE_BALANCE_AUTO, wbMode) == 0));
 
-            const char *effect = cameraParams.get(CameraParameters::KEY_EFFECT);
-            ASSERT_TRUE((nullptr == effect) || (strcmp(
-                    CameraParameters::EFFECT_NONE, effect) == 0));
+                const char *effect = cameraParams.get(
+                        CameraParameters::KEY_EFFECT);
+                ASSERT_TRUE((nullptr == effect) || (strcmp(
+                        CameraParameters::EFFECT_NONE, effect) == 0));
 
-            ::android::Vector<Size> previewSizes;
-            cameraParams.getSupportedPreviewSizes(previewSizes);
-            ASSERT_FALSE(previewSizes.empty());
-            ::android::Vector<Size> pictureSizes;
-            cameraParams.getSupportedPictureSizes(pictureSizes);
-            ASSERT_FALSE(pictureSizes.empty());
-            const char *previewFormats = cameraParams.get(
-                    CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
-            ASSERT_NE(nullptr, previewFormats);
-            ::android::String8 previewFormatsString(previewFormats);
-            ASSERT_TRUE(previewFormatsString.contains(
-                    CameraParameters::PIXEL_FORMAT_YUV420SP));
-            ASSERT_NE(nullptr, cameraParams.get(
-                    CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS));
-            ASSERT_NE(nullptr, cameraParams.get(
-                    CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES));
-            const char *focusModes = cameraParams.get(
-                    CameraParameters::KEY_SUPPORTED_FOCUS_MODES);
-            ASSERT_NE(nullptr, focusModes);
-            ::android::String8 focusModesString(focusModes);
-            const char *focusMode = cameraParams.get(
-                    CameraParameters::KEY_FOCUS_MODE);
-            ASSERT_NE(nullptr, focusMode);
-            // Auto focus mode should be default
-            if (focusModesString.contains(CameraParameters::FOCUS_MODE_AUTO)) {
-                ASSERT_TRUE(strcmp(
-                        CameraParameters::FOCUS_MODE_AUTO, focusMode) == 0);
+                ::android::Vector<Size> previewSizes;
+                cameraParams.getSupportedPreviewSizes(previewSizes);
+                ASSERT_FALSE(previewSizes.empty());
+                ::android::Vector<Size> pictureSizes;
+                cameraParams.getSupportedPictureSizes(pictureSizes);
+                ASSERT_FALSE(pictureSizes.empty());
+                const char *previewFormats = cameraParams.get(
+                        CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS);
+                ASSERT_NE(nullptr, previewFormats);
+                ::android::String8 previewFormatsString(previewFormats);
+                ASSERT_TRUE(previewFormatsString.contains(
+                        CameraParameters::PIXEL_FORMAT_YUV420SP));
+                ASSERT_NE(nullptr, cameraParams.get(
+                        CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS));
+                ASSERT_NE(nullptr, cameraParams.get(
+                        CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES));
+                const char *focusModes = cameraParams.get(
+                        CameraParameters::KEY_SUPPORTED_FOCUS_MODES);
+                ASSERT_NE(nullptr, focusModes);
+                ::android::String8 focusModesString(focusModes);
+                const char *focusMode = cameraParams.get(
+                        CameraParameters::KEY_FOCUS_MODE);
+                ASSERT_NE(nullptr, focusMode);
+                // Auto focus mode should be default
+                if (focusModesString.contains(
+                        CameraParameters::FOCUS_MODE_AUTO)) {
+                    ASSERT_TRUE(strcmp(
+                            CameraParameters::FOCUS_MODE_AUTO, focusMode) == 0);
+                }
+                ASSERT_TRUE(0 < cameraParams.getInt(
+                        CameraParameters::KEY_FOCAL_LENGTH));
+                int32_t horizontalViewAngle = cameraParams.getInt(
+                        CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE);
+                ASSERT_TRUE((0 < horizontalViewAngle) &&
+                            (360 >= horizontalViewAngle));
+                int32_t verticalViewAngle = cameraParams.getInt(
+                        CameraParameters::KEY_VERTICAL_VIEW_ANGLE);
+                ASSERT_TRUE((0 < verticalViewAngle) &&
+                            (360 >= verticalViewAngle));
+                int32_t jpegQuality = cameraParams.getInt(
+                        CameraParameters::KEY_JPEG_QUALITY);
+                ASSERT_TRUE((1 <= jpegQuality) && (100 >= jpegQuality));
+                int32_t jpegThumbQuality = cameraParams.getInt(
+                        CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY);
+                ASSERT_TRUE((1 <= jpegThumbQuality) &&
+                            (100 >= jpegThumbQuality));
+
+                cameraParams.setPictureSize(pictureSizes[0].width,
+                        pictureSizes[0].height);
+                cameraParams.setPreviewSize(previewSizes[0].width,
+                        previewSizes[0].height);
+
+                setParameters(device1, cameraParams);
+                getParameters(device1, &cameraParams /*out*/);
+
+                cameraParams.getPictureSize(&width, &height);
+                ASSERT_TRUE((pictureSizes[0].width == width) &&
+                        (pictureSizes[0].height == height));
+                cameraParams.getPreviewSize(&width, &height);
+                ASSERT_TRUE((previewSizes[0].width == width) &&
+                        (previewSizes[0].height == height));
+
+                Return<void> ret = device1->close();
+                ASSERT_TRUE(ret.isOk());
             }
-            ASSERT_TRUE(0 < cameraParams.getInt(
-                    CameraParameters::KEY_FOCAL_LENGTH));
-            int32_t horizontalViewAngle = cameraParams.getInt(
-                    CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE);
-            ASSERT_TRUE((0 < horizontalViewAngle) && (360 >= horizontalViewAngle));
-            int32_t verticalViewAngle = cameraParams.getInt(
-                    CameraParameters::KEY_VERTICAL_VIEW_ANGLE);
-            ASSERT_TRUE((0 < verticalViewAngle) && (360 >= verticalViewAngle));
-            int32_t jpegQuality = cameraParams.getInt(
-                    CameraParameters::KEY_JPEG_QUALITY);
-            ASSERT_TRUE((1 <= jpegQuality) && (100 >= jpegQuality));
-            int32_t jpegThumbQuality = cameraParams.getInt(
-                    CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY);
-            ASSERT_TRUE((1 <= jpegThumbQuality) && (100 >= jpegThumbQuality));
-
-            cameraParams.setPictureSize(pictureSizes[0].width,
-                    pictureSizes[0].height);
-            cameraParams.setPreviewSize(previewSizes[0].width,
-                    previewSizes[0].height);
-
-            setParameters(device1, cameraParams);
-            getParameters(device1, &cameraParams /*out*/);
-
-            cameraParams.getPictureSize(&width, &height);
-            ASSERT_TRUE((pictureSizes[0].width == width) &&
-                    (pictureSizes[0].height == height));
-            cameraParams.getPreviewSize(&width, &height);
-            ASSERT_TRUE((previewSizes[0].width == width) &&
-                    (previewSizes[0].height == height));
-
-            Return<void> ret = device1->close();
-            ASSERT_TRUE(ret.isOk());
         }
     }
 }
@@ -1852,39 +2011,50 @@
 // Verify that the static camera characteristics can be retrieved
 // successfully.
 TEST_F(CameraHidlTest, getCameraCharacteristics) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
-            ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
-            Return<void> ret;
-            ret = env->mProvider->getCameraDeviceInterface_V3_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device3_2 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+                ALOGI("getCameraCharacteristics: Testing camera device %s",
+                      name.c_str());
+                Return<void> ret;
+                ret = provider.second->getCameraDeviceInterface_V3_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device3_2 = device;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            ret = device3_2->getCameraCharacteristics(
-                [&](auto status, const auto& chars) {
-                    ALOGI("getCameraCharacteristics returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    const camera_metadata_t* metadata = (camera_metadata_t*) chars.data();
-                    size_t expectedSize = chars.size();
-                    int result = validate_camera_metadata_structure(metadata, &expectedSize);
-                    ASSERT_TRUE(result == 0 || result == CAMERA_METADATA_VALIDATION_SHIFTED);
-                    size_t entryCount = get_camera_metadata_entry_count(metadata);
-                    // TODO: we can do better than 0 here. Need to check how many required
-                    // characteristics keys we've defined.
-                    ASSERT_GT(entryCount, 0u);
-                    ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount);
-                });
-            ASSERT_TRUE(ret.isOk());
+                ret = device3_2->getCameraCharacteristics(
+                    [&](auto status, const auto& chars) {
+                        ALOGI("getCameraCharacteristics returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        const camera_metadata_t* metadata =
+                                (camera_metadata_t*) chars.data();
+                        size_t expectedSize = chars.size();
+                        int result = validate_camera_metadata_structure(
+                                metadata, &expectedSize);
+                        ASSERT_TRUE((result == 0) ||
+                                (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+                        size_t entryCount = get_camera_metadata_entry_count(
+                                metadata);
+                        // TODO: we can do better than 0 here. Need to check how many required
+                        // characteristics keys we've defined.
+                        ASSERT_GT(entryCount, 0u);
+                        ALOGI("getCameraCharacteristics metadata entry count is %zu",
+                              entryCount);
+                    });
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
@@ -1892,252 +2062,273 @@
 //In case it is supported verify that torch can be enabled.
 //Check for corresponding toch callbacks as well.
 TEST_F(CameraHidlTest, setTorchMode) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    bool torchControlSupported = false;
-    Return<void> ret;
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        bool torchControlSupported = false;
+        Return<void> ret;
 
-    ret = CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
-        [&](auto status, bool support) {
-            ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
-                    (int)status, support);
-            ASSERT_EQ(Status::OK, status);
-            torchControlSupported = support;
-        });
+        ret = provider.second->isSetTorchModeSupported(
+            [&](auto status, bool support) {
+                ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
+                        (int)status, support);
+                ASSERT_EQ(Status::OK, status);
+                torchControlSupported = support;
+            });
 
 
-    sp<TorchProviderCb> cb = new TorchProviderCb(this);
-    Return<Status> returnStatus = env->mProvider->setCallback(cb);
-    ASSERT_TRUE(returnStatus.isOk());
-    ASSERT_EQ(Status::OK, returnStatus);
+        sp<TorchProviderCb> cb = new TorchProviderCb(this);
+        Return<Status> returnStatus = provider.second->setCallback(cb);
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, returnStatus);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
-            ALOGI("setTorchMode: Testing camera device %s", name.c_str());
-            ret = env->mProvider->getCameraDeviceInterface_V3_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device3_2 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+                ALOGI("setTorchMode: Testing camera device %s", name.c_str());
+                ret = provider.second->getCameraDeviceInterface_V3_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device3_2 = device;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
-            returnStatus = device3_2->setTorchMode(TorchMode::ON);
-            ASSERT_TRUE(returnStatus.isOk());
-            if (!torchControlSupported) {
-                ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
-            } else {
-                ASSERT_TRUE(returnStatus == Status::OK ||
-                            returnStatus == Status::OPERATION_NOT_SUPPORTED);
-                if (returnStatus == Status::OK) {
-                    {
-                        std::unique_lock<std::mutex> l(mTorchLock);
-                        while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
-                            auto timeout = std::chrono::system_clock::now() +
-                                    std::chrono::seconds(kTorchTimeoutSec);
-                            ASSERT_NE(std::cv_status::timeout,
-                                    mTorchCond.wait_until(l, timeout));
+                mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+                returnStatus = device3_2->setTorchMode(TorchMode::ON);
+                ASSERT_TRUE(returnStatus.isOk());
+                if (!torchControlSupported) {
+                    ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
+                } else {
+                    ASSERT_TRUE(returnStatus == Status::OK ||
+                                returnStatus == Status::OPERATION_NOT_SUPPORTED);
+                    if (returnStatus == Status::OK) {
+                        {
+                            std::unique_lock<std::mutex> l(mTorchLock);
+                            while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+                                auto timeout = std::chrono::system_clock::now() +
+                                        std::chrono::seconds(kTorchTimeoutSec);
+                                ASSERT_NE(std::cv_status::timeout,
+                                        mTorchCond.wait_until(l, timeout));
+                            }
+                            ASSERT_EQ(TorchModeStatus::AVAILABLE_ON,
+                                    mTorchStatus);
+                            mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
                         }
-                        ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
-                        mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
-                    }
 
-                    returnStatus = device3_2->setTorchMode(TorchMode::OFF);
-                    ASSERT_TRUE(returnStatus.isOk());
-                    ASSERT_EQ(Status::OK, returnStatus);
+                        returnStatus = device3_2->setTorchMode(TorchMode::OFF);
+                        ASSERT_TRUE(returnStatus.isOk());
+                        ASSERT_EQ(Status::OK, returnStatus);
 
-                    {
-                        std::unique_lock<std::mutex> l(mTorchLock);
-                        while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
-                            auto timeout = std::chrono::system_clock::now() +
-                                    std::chrono::seconds(kTorchTimeoutSec);
-                            ASSERT_NE(std::cv_status::timeout,
-                                    mTorchCond.wait_until(l, timeout));
+                        {
+                            std::unique_lock<std::mutex> l(mTorchLock);
+                            while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+                                auto timeout = std::chrono::system_clock::now() +
+                                        std::chrono::seconds(kTorchTimeoutSec);
+                                ASSERT_NE(std::cv_status::timeout,
+                                        mTorchCond.wait_until(l, timeout));
+                            }
+                            ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF,
+                                    mTorchStatus);
                         }
-                        ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
                     }
                 }
-            }
-        } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            ALOGI("dumpState: Testing camera device %s", name.c_str());
-            ret = env->mProvider->getCameraDeviceInterface_V1_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device1 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
+            } else if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                ALOGI("dumpState: Testing camera device %s", name.c_str());
+                ret = provider.second->getCameraDeviceInterface_V1_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device1 = device;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
-            returnStatus = device1->setTorchMode(TorchMode::ON);
-            ASSERT_TRUE(returnStatus.isOk());
-            if (!torchControlSupported) {
-                ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
-            } else {
-                ASSERT_TRUE(returnStatus == Status::OK ||
-                            returnStatus == Status::OPERATION_NOT_SUPPORTED);
-                if (returnStatus == Status::OK) {
-                    {
-                        std::unique_lock<std::mutex> l(mTorchLock);
-                        while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
-                            auto timeout = std::chrono::system_clock::now() +
-                                    std::chrono::seconds(kTorchTimeoutSec);
-                            ASSERT_NE(std::cv_status::timeout,
-                                    mTorchCond.wait_until(l, timeout));
+                mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
+                returnStatus = device1->setTorchMode(TorchMode::ON);
+                ASSERT_TRUE(returnStatus.isOk());
+                if (!torchControlSupported) {
+                    ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
+                } else {
+                    ASSERT_TRUE(returnStatus == Status::OK ||
+                                returnStatus == Status::OPERATION_NOT_SUPPORTED);
+                    if (returnStatus == Status::OK) {
+                        {
+                            std::unique_lock<std::mutex> l(mTorchLock);
+                            while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+                                auto timeout = std::chrono::system_clock::now() +
+                                        std::chrono::seconds(kTorchTimeoutSec);
+                                ASSERT_NE(std::cv_status::timeout,
+                                        mTorchCond.wait_until(l, timeout));
+                            }
+                            ASSERT_EQ(TorchModeStatus::AVAILABLE_ON,
+                                    mTorchStatus);
+                            mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
                         }
-                        ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
-                        mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
-                    }
 
-                    returnStatus = device1->setTorchMode(TorchMode::OFF);
-                    ASSERT_TRUE(returnStatus.isOk());
-                    ASSERT_EQ(Status::OK, returnStatus);
+                        returnStatus = device1->setTorchMode(TorchMode::OFF);
+                        ASSERT_TRUE(returnStatus.isOk());
+                        ASSERT_EQ(Status::OK, returnStatus);
 
-                    {
-                        std::unique_lock<std::mutex> l(mTorchLock);
-                        while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
-                            auto timeout = std::chrono::system_clock::now() +
-                                    std::chrono::seconds(kTorchTimeoutSec);
-                            ASSERT_NE(std::cv_status::timeout,
-                                    mTorchCond.wait_until(l, timeout));
+                        {
+                            std::unique_lock<std::mutex> l(mTorchLock);
+                            while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
+                                auto timeout = std::chrono::system_clock::now() +
+                                        std::chrono::seconds(kTorchTimeoutSec);
+                                ASSERT_NE(std::cv_status::timeout,
+                                        mTorchCond.wait_until(l, timeout));
+                            }
+                            ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF,
+                                    mTorchStatus);
                         }
-                        ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
                     }
                 }
+                ret = device1->close();
+                ASSERT_TRUE(ret.isOk());
             }
-            ret = device1->close();
-            ASSERT_TRUE(ret.isOk());
         }
-    }
 
-    returnStatus = env->mProvider->setCallback(nullptr);
-    ASSERT_TRUE(returnStatus.isOk());
-    ASSERT_EQ(Status::OK, returnStatus);
+        returnStatus = provider.second->setCallback(nullptr);
+        ASSERT_TRUE(returnStatus.isOk());
+        ASSERT_EQ(Status::OK, returnStatus);
+    }
 }
 
 // Check dump functionality.
 TEST_F(CameraHidlTest, dumpState) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    Return<void> ret;
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        Return<void> ret;
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
-            ALOGI("dumpState: Testing camera device %s", name.c_str());
-            ret = env->mProvider->getCameraDeviceInterface_V3_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device3_2 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                ::android::sp<ICameraDevice> device3_2;
+                ALOGI("dumpState: Testing camera device %s", name.c_str());
+                ret = provider.second->getCameraDeviceInterface_V3_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device3_2 = device;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            native_handle_t* raw_handle = native_handle_create(1, 0);
-            raw_handle->data[0] = open(kDumpOutput, O_RDWR);
-            ASSERT_GE(raw_handle->data[0], 0);
-            hidl_handle handle = raw_handle;
-            ret= device3_2->dumpState(handle);
-            ASSERT_TRUE(ret.isOk());
-            close(raw_handle->data[0]);
-            native_handle_delete(raw_handle);
-        } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            ALOGI("dumpState: Testing camera device %s", name.c_str());
-            ret = env->mProvider->getCameraDeviceInterface_V1_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V1_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device1 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
+                native_handle_t* raw_handle = native_handle_create(1, 0);
+                raw_handle->data[0] = open(kDumpOutput, O_RDWR);
+                ASSERT_GE(raw_handle->data[0], 0);
+                hidl_handle handle = raw_handle;
+                ret= device3_2->dumpState(handle);
+                ASSERT_TRUE(ret.isOk());
+                close(raw_handle->data[0]);
+                native_handle_delete(raw_handle);
+            } else if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                ::android::sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                ALOGI("dumpState: Testing camera device %s", name.c_str());
+                ret = provider.second->getCameraDeviceInterface_V1_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device1 = device;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            native_handle_t* raw_handle = native_handle_create(1, 0);
-            raw_handle->data[0] = open(kDumpOutput, O_RDWR);
-            ASSERT_GE(raw_handle->data[0], 0);
-            hidl_handle handle = raw_handle;
-            Return<Status> returnStatus = device1->dumpState(handle);
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
-            close(raw_handle->data[0]);
-            native_handle_delete(raw_handle);
+                native_handle_t* raw_handle = native_handle_create(1, 0);
+                raw_handle->data[0] = open(kDumpOutput, O_RDWR);
+                ASSERT_GE(raw_handle->data[0], 0);
+                hidl_handle handle = raw_handle;
+                Return<Status> returnStatus = device1->dumpState(handle);
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
+                close(raw_handle->data[0]);
+                native_handle_delete(raw_handle);
+            }
         }
     }
 }
 
 // Open, dumpStates, then close
 TEST_F(CameraHidlTest, openClose) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    Return<void> ret;
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        Return<void> ret;
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
-            ALOGI("openClose: Testing camera device %s", name.c_str());
-            ret = env->mProvider->getCameraDeviceInterface_V3_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device3_2 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+                ALOGI("openClose: Testing camera device %s", name.c_str());
+                ret = provider.second->getCameraDeviceInterface_V3_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device3_2 = device;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
-            sp<ICameraDeviceSession> session;
-            ret = device3_2->open(
-                cb,
-                [&](auto status, const auto& newSession) {
-                    ALOGI("device::open returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(newSession, nullptr);
-                    session = newSession;
-                });
-            ASSERT_TRUE(ret.isOk());
+                sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
+                sp<ICameraDeviceSession> session;
+                ret = device3_2->open(
+                    cb,
+                    [&](auto status, const auto& newSession) {
+                        ALOGI("device::open returns status:%d", (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(newSession, nullptr);
+                        session = newSession;
+                    });
+                ASSERT_TRUE(ret.isOk());
 
-            native_handle_t* raw_handle = native_handle_create(1, 0);
-            raw_handle->data[0] = open(kDumpOutput, O_RDWR);
-            ASSERT_GE(raw_handle->data[0], 0);
-            hidl_handle handle = raw_handle;
-            ret = device3_2->dumpState(handle);
-            ASSERT_TRUE(ret.isOk());
-            close(raw_handle->data[0]);
-            native_handle_delete(raw_handle);
+                native_handle_t* raw_handle = native_handle_create(1, 0);
+                raw_handle->data[0] = open(kDumpOutput, O_RDWR);
+                ASSERT_GE(raw_handle->data[0], 0);
+                hidl_handle handle = raw_handle;
+                ret = device3_2->dumpState(handle);
+                ASSERT_TRUE(ret.isOk());
+                close(raw_handle->data[0]);
+                native_handle_delete(raw_handle);
 
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
-            // TODO: test all session API calls return INTERNAL_ERROR after close
-            // TODO: keep a wp copy here and verify session cannot be promoted out of this scope
-        } else if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_1_0) {
-            sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
-            openCameraDevice(name, env, &device1 /*out*/);
-            ASSERT_NE(nullptr, device1.get());
+                ret = session->close();
+                ASSERT_TRUE(ret.isOk());
+                // TODO: test all session API calls return INTERNAL_ERROR after close
+                // TODO: keep a wp copy here and verify session cannot be promoted out of this scope
+            } else if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_1_0) {
+                sp<::android::hardware::camera::device::V1_0::ICameraDevice> device1;
+                openCameraDevice(name, provider.second, &device1 /*out*/);
+                ASSERT_NE(nullptr, device1.get());
 
-            native_handle_t* raw_handle = native_handle_create(1, 0);
-            raw_handle->data[0] = open(kDumpOutput, O_RDWR);
-            ASSERT_GE(raw_handle->data[0], 0);
-            hidl_handle handle = raw_handle;
-            Return<Status> returnStatus = device1->dumpState(handle);
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
-            close(raw_handle->data[0]);
-            native_handle_delete(raw_handle);
+                native_handle_t* raw_handle = native_handle_create(1, 0);
+                raw_handle->data[0] = open(kDumpOutput, O_RDWR);
+                ASSERT_GE(raw_handle->data[0], 0);
+                hidl_handle handle = raw_handle;
+                Return<Status> returnStatus = device1->dumpState(handle);
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
+                close(raw_handle->data[0]);
+                native_handle_delete(raw_handle);
 
-            ret = device1->close();
-            ASSERT_TRUE(ret.isOk());
+                ret = device1->close();
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
@@ -2145,71 +2336,81 @@
 // Check whether all common default request settings can be sucessfully
 // constructed.
 TEST_F(CameraHidlTest, constructDefaultRequestSettings) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
-            Return<void> ret;
-            ALOGI("constructDefaultRequestSettings: Testing camera device %s", name.c_str());
-            ret = env->mProvider->getCameraDeviceInterface_V3_x(
-                name,
-                [&](auto status, const auto& device) {
-                    ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(device, nullptr);
-                    device3_2 = device;
-                });
-            ASSERT_TRUE(ret.isOk());
-
-            sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
-            sp<ICameraDeviceSession> session;
-            ret = device3_2->open(
-                cb,
-                [&](auto status, const auto& newSession) {
-                    ALOGI("device::open returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    ASSERT_NE(newSession, nullptr);
-                    session = newSession;
-                });
-            ASSERT_TRUE(ret.isOk());
-
-            for (uint32_t t = (uint32_t) RequestTemplate::PREVIEW;
-                    t <= (uint32_t) RequestTemplate::MANUAL; t++) {
-                RequestTemplate reqTemplate = (RequestTemplate) t;
-                ret = session->constructDefaultRequestSettings(
-                    reqTemplate,
-                    [&](auto status, const auto& req) {
-                        ALOGI("constructDefaultRequestSettings returns status:%d", (int)status);
-                        if (reqTemplate == RequestTemplate::ZERO_SHUTTER_LAG ||
-                                reqTemplate == RequestTemplate::MANUAL) {
-                            // optional templates
-                            ASSERT_TRUE(status == Status::OK || status == Status::ILLEGAL_ARGUMENT);
-                        } else {
-                            ASSERT_EQ(Status::OK, status);
-                        }
-
-                        if (status == Status::OK) {
-                            const camera_metadata_t* metadata =
-                                (camera_metadata_t*) req.data();
-                            size_t expectedSize = req.size();
-                            int result = validate_camera_metadata_structure(
-                                    metadata, &expectedSize);
-                            ASSERT_TRUE(result == 0 || result == CAMERA_METADATA_VALIDATION_SHIFTED);
-                            size_t entryCount = get_camera_metadata_entry_count(metadata);
-                            // TODO: we can do better than 0 here. Need to check how many required
-                            // request keys we've defined for each template
-                            ASSERT_GT(entryCount, 0u);
-                            ALOGI("template %u metadata entry count is %zu", t, entryCount);
-                        } else {
-                            ASSERT_EQ(0u, req.size());
-                        }
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+                Return<void> ret;
+                ALOGI("constructDefaultRequestSettings: Testing camera device %s",
+                      name.c_str());
+                ret = provider.second->getCameraDeviceInterface_V3_x(
+                    name,
+                    [&](auto status, const auto& device) {
+                        ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+                              (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(device, nullptr);
+                        device3_2 = device;
                     });
                 ASSERT_TRUE(ret.isOk());
+
+                sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
+                sp<ICameraDeviceSession> session;
+                ret = device3_2->open(
+                    cb,
+                    [&](auto status, const auto& newSession) {
+                        ALOGI("device::open returns status:%d", (int)status);
+                        ASSERT_EQ(Status::OK, status);
+                        ASSERT_NE(newSession, nullptr);
+                        session = newSession;
+                    });
+                ASSERT_TRUE(ret.isOk());
+
+                for (uint32_t t = (uint32_t) RequestTemplate::PREVIEW;
+                        t <= (uint32_t) RequestTemplate::MANUAL; t++) {
+                    RequestTemplate reqTemplate = (RequestTemplate) t;
+                    ret = session->constructDefaultRequestSettings(
+                        reqTemplate,
+                        [&](auto status, const auto& req) {
+                            ALOGI("constructDefaultRequestSettings returns status:%d",
+                                  (int)status);
+                            if (reqTemplate == RequestTemplate::ZERO_SHUTTER_LAG ||
+                                    reqTemplate == RequestTemplate::MANUAL) {
+                                // optional templates
+                                ASSERT_TRUE((status == Status::OK) ||
+                                        (status == Status::ILLEGAL_ARGUMENT));
+                            } else {
+                                ASSERT_EQ(Status::OK, status);
+                            }
+
+                            if (status == Status::OK) {
+                                const camera_metadata_t* metadata =
+                                    (camera_metadata_t*) req.data();
+                                size_t expectedSize = req.size();
+                                int result = validate_camera_metadata_structure(
+                                        metadata, &expectedSize);
+                                ASSERT_TRUE((result == 0) ||
+                                        (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+                                size_t entryCount =
+                                        get_camera_metadata_entry_count(metadata);
+                                // TODO: we can do better than 0 here. Need to check how many required
+                                // request keys we've defined for each template
+                                ASSERT_GT(entryCount, 0u);
+                                ALOGI("template %u metadata entry count is %zu",
+                                      t, entryCount);
+                            } else {
+                                ASSERT_EQ(0u, req.size());
+                            }
+                        });
+                    ASSERT_TRUE(ret.isOk());
+                }
+                ret = session->close();
+                ASSERT_TRUE(ret.isOk());
             }
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
         }
     }
 }
@@ -2217,104 +2418,94 @@
 // Verify that all supported stream formats and sizes can be configured
 // successfully.
 TEST_F(CameraHidlTest, configureStreamsAvailableOutputs) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    std::vector<AvailableStream> outputStreams;
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        std::vector<AvailableStream> outputStreams;
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            camera_metadata_t *staticMeta;
-            Return<void> ret;
-            sp<ICameraDeviceSession> session;
-            openEmptyDeviceSession(name, env, &session /*out*/,
-                    &staticMeta /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                camera_metadata_t *staticMeta;
+                Return<void> ret;
+                sp<ICameraDeviceSession> session;
+                openEmptyDeviceSession(name, provider.second, &session /*out*/,
+                        &staticMeta /*out*/);
 
-            outputStreams.clear();
-            ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
-                    outputStreams));
-            ASSERT_NE(0u, outputStreams.size());
+                outputStreams.clear();
+                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+                        outputStreams));
+                ASSERT_NE(0u, outputStreams.size());
 
-            int32_t streamId = 0;
-            for (auto &it : outputStreams) {
-                Stream stream = {streamId, StreamType::OUTPUT,
-                        static_cast<uint32_t> (it.width),
-                        static_cast<uint32_t> (it.height),
-                        static_cast<PixelFormat> (it.format), 0, 0,
-                        StreamRotation::ROTATION_0};
-                ::android::hardware::hidl_vec<Stream> streams = {stream};
-                StreamConfiguration config = {streams,
-                        StreamConfigurationMode::NORMAL_MODE};
-                ret = session->configureStreams(config, [streamId] (Status s,
-                        HalStreamConfiguration halConfig) {
-                    ASSERT_EQ(Status::OK, s);
-                    ASSERT_EQ(1u, halConfig.streams.size());
-                    ASSERT_EQ(halConfig.streams[0].id, streamId);
-                });
+                int32_t streamId = 0;
+                for (auto &it : outputStreams) {
+                    Stream stream = {streamId, StreamType::OUTPUT,
+                            static_cast<uint32_t> (it.width),
+                            static_cast<uint32_t> (it.height),
+                            static_cast<PixelFormat> (it.format), 0, 0,
+                            StreamRotation::ROTATION_0};
+                    ::android::hardware::hidl_vec<Stream> streams = {stream};
+                    StreamConfiguration config = {streams,
+                            StreamConfigurationMode::NORMAL_MODE};
+                    ret = session->configureStreams(config, [streamId] (Status s,
+                            HalStreamConfiguration halConfig) {
+                        ASSERT_EQ(Status::OK, s);
+                        ASSERT_EQ(1u, halConfig.streams.size());
+                        ASSERT_EQ(halConfig.streams[0].id, streamId);
+                    });
+                    ASSERT_TRUE(ret.isOk());
+                    streamId++;
+                }
+
+                free_camera_metadata(staticMeta);
+                ret = session->close();
                 ASSERT_TRUE(ret.isOk());
-                streamId++;
             }
-
-            free_camera_metadata(staticMeta);
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
         }
     }
 }
 
 // Check for correct handling of invalid/incorrect configuration parameters.
 TEST_F(CameraHidlTest, configureStreamsInvalidOutputs) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    std::vector<AvailableStream> outputStreams;
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        std::vector<AvailableStream> outputStreams;
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            camera_metadata_t *staticMeta;
-            Return<void> ret;
-            sp<ICameraDeviceSession> session;
-            openEmptyDeviceSession(name, env, &session /*out*/,
-                    &staticMeta /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                camera_metadata_t *staticMeta;
+                Return<void> ret;
+                sp<ICameraDeviceSession> session;
+                openEmptyDeviceSession(name, provider.second, &session /*out*/,
+                        &staticMeta /*out*/);
 
-            outputStreams.clear();
-            ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
-                    outputStreams));
-            ASSERT_NE(0u, outputStreams.size());
+                outputStreams.clear();
+                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+                        outputStreams));
+                ASSERT_NE(0u, outputStreams.size());
 
-            int32_t streamId = 0;
-            Stream stream = {streamId++, StreamType::OUTPUT,
-                    static_cast<uint32_t> (0),
-                    static_cast<uint32_t> (0),
-                    static_cast<PixelFormat> (outputStreams[0].format),
-                    0, 0, StreamRotation::ROTATION_0};
-            ::android::hardware::hidl_vec<Stream> streams = {stream};
-            StreamConfiguration config = {streams,
-                    StreamConfigurationMode::NORMAL_MODE};
-            ret = session->configureStreams(config, [] (Status s,
-                    HalStreamConfiguration) {
-                ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                            (Status::INTERNAL_ERROR == s));
-            });
-            ASSERT_TRUE(ret.isOk());
+                int32_t streamId = 0;
+                Stream stream = {streamId++, StreamType::OUTPUT,
+                        static_cast<uint32_t> (0),
+                        static_cast<uint32_t> (0),
+                        static_cast<PixelFormat> (outputStreams[0].format),
+                        0, 0, StreamRotation::ROTATION_0};
+                ::android::hardware::hidl_vec<Stream> streams = {stream};
+                StreamConfiguration config = {streams,
+                        StreamConfigurationMode::NORMAL_MODE};
+                ret = session->configureStreams(config, [] (Status s,
+                        HalStreamConfiguration) {
+                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                });
+                ASSERT_TRUE(ret.isOk());
 
-            stream = {streamId++, StreamType::OUTPUT,
-                    static_cast<uint32_t> (UINT32_MAX),
-                    static_cast<uint32_t> (UINT32_MAX),
-                    static_cast<PixelFormat> (outputStreams[0].format),
-                    0, 0, StreamRotation::ROTATION_0};
-            streams[0] = stream;
-            config = {streams,
-                    StreamConfigurationMode::NORMAL_MODE};
-            ret = session->configureStreams(config, [] (Status s,
-                    HalStreamConfiguration) {
-                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-            });
-            ASSERT_TRUE(ret.isOk());
-
-            for (auto &it : outputStreams) {
                 stream = {streamId++, StreamType::OUTPUT,
-                        static_cast<uint32_t> (it.width),
-                        static_cast<uint32_t> (it.height),
-                        static_cast<PixelFormat> (UINT32_MAX),
+                        static_cast<uint32_t> (UINT32_MAX),
+                        static_cast<uint32_t> (UINT32_MAX),
+                        static_cast<PixelFormat> (outputStreams[0].format),
                         0, 0, StreamRotation::ROTATION_0};
                 streams[0] = stream;
                 config = {streams,
@@ -2325,24 +2516,40 @@
                 });
                 ASSERT_TRUE(ret.isOk());
 
-                stream = {streamId++, StreamType::OUTPUT,
-                        static_cast<uint32_t> (it.width),
-                        static_cast<uint32_t> (it.height),
-                        static_cast<PixelFormat> (it.format),
-                        0, 0, static_cast<StreamRotation> (UINT32_MAX)};
-                streams[0] = stream;
-                config = {streams,
-                        StreamConfigurationMode::NORMAL_MODE};
-                ret = session->configureStreams(config, [] (Status s,
-                        HalStreamConfiguration) {
-                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-                });
+                for (auto &it : outputStreams) {
+                    stream = {streamId++, StreamType::OUTPUT,
+                            static_cast<uint32_t> (it.width),
+                            static_cast<uint32_t> (it.height),
+                            static_cast<PixelFormat> (UINT32_MAX),
+                            0, 0, StreamRotation::ROTATION_0};
+                    streams[0] = stream;
+                    config = {streams,
+                            StreamConfigurationMode::NORMAL_MODE};
+                    ret = session->configureStreams(config, [] (Status s,
+                            HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+                    ASSERT_TRUE(ret.isOk());
+
+                    stream = {streamId++, StreamType::OUTPUT,
+                            static_cast<uint32_t> (it.width),
+                            static_cast<uint32_t> (it.height),
+                            static_cast<PixelFormat> (it.format),
+                            0, 0, static_cast<StreamRotation> (UINT32_MAX)};
+                    streams[0] = stream;
+                    config = {streams,
+                            StreamConfigurationMode::NORMAL_MODE};
+                    ret = session->configureStreams(config, [] (Status s,
+                            HalStreamConfiguration) {
+                        ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                    });
+                    ASSERT_TRUE(ret.isOk());
+                }
+
+                free_camera_metadata(staticMeta);
+                ret = session->close();
                 ASSERT_TRUE(ret.isOk());
             }
-
-            free_camera_metadata(staticMeta);
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
         }
     }
 }
@@ -2350,83 +2557,86 @@
 // Check whether all supported ZSL output stream combinations can be
 // configured successfully.
 TEST_F(CameraHidlTest, configureStreamsZSLInputOutputs) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    std::vector<AvailableStream> inputStreams;
-    std::vector<AvailableZSLInputOutput> inputOutputMap;
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        std::vector<AvailableStream> inputStreams;
+        std::vector<AvailableZSLInputOutput> inputOutputMap;
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            camera_metadata_t *staticMeta;
-            Return<void> ret;
-            sp<ICameraDeviceSession> session;
-            openEmptyDeviceSession(name, env, &session /*out*/,
-                    &staticMeta /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                camera_metadata_t *staticMeta;
+                Return<void> ret;
+                sp<ICameraDeviceSession> session;
+                openEmptyDeviceSession(name, provider.second, &session /*out*/,
+                        &staticMeta /*out*/);
 
-            Status rc = isZSLModeAvailable(staticMeta);
-            if (Status::METHOD_NOT_SUPPORTED == rc) {
-                ret = session->close();
-                ASSERT_TRUE(ret.isOk());
-                continue;
-            }
-            ASSERT_EQ(Status::OK, rc);
+                Status rc = isZSLModeAvailable(staticMeta);
+                if (Status::METHOD_NOT_SUPPORTED == rc) {
+                    ret = session->close();
+                    ASSERT_TRUE(ret.isOk());
+                    continue;
+                }
+                ASSERT_EQ(Status::OK, rc);
 
-            inputStreams.clear();
-            ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
-                    inputStreams));
-            ASSERT_NE(0u, inputStreams.size());
-
-            inputOutputMap.clear();
-            ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta,
-                    inputOutputMap));
-            ASSERT_NE(0u, inputOutputMap.size());
-
-            int32_t streamId = 0;
-            for (auto &inputIter : inputOutputMap) {
-                AvailableStream input;
-                ASSERT_EQ(Status::OK,
-                        findLargestSize(inputStreams, inputIter.inputFormat, input));
+                inputStreams.clear();
+                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+                        inputStreams));
                 ASSERT_NE(0u, inputStreams.size());
 
-                AvailableStream outputThreshold = {INT32_MAX, INT32_MAX,
-                        inputIter.outputFormat};
-                std::vector<AvailableStream> outputStreams;
-                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
-                        outputStreams, &outputThreshold));
-                for (auto &outputIter : outputStreams) {
-                    Stream zslStream = {streamId++, StreamType::OUTPUT,
-                            static_cast<uint32_t> (input.width),
-                            static_cast<uint32_t> (input.height),
-                            static_cast<PixelFormat> (input.format),
-                            GRALLOC_USAGE_HW_CAMERA_ZSL, 0,
-                            StreamRotation::ROTATION_0};
-                    Stream inputStream = {streamId++, StreamType::INPUT,
-                            static_cast<uint32_t> (input.width),
-                            static_cast<uint32_t> (input.height),
-                            static_cast<PixelFormat> (input.format), 0, 0,
-                            StreamRotation::ROTATION_0};
-                    Stream outputStream = {streamId++, StreamType::OUTPUT,
-                            static_cast<uint32_t> (outputIter.width),
-                            static_cast<uint32_t> (outputIter.height),
-                            static_cast<PixelFormat> (outputIter.format), 0, 0,
-                            StreamRotation::ROTATION_0};
+                inputOutputMap.clear();
+                ASSERT_EQ(Status::OK, getZSLInputOutputMap(staticMeta,
+                        inputOutputMap));
+                ASSERT_NE(0u, inputOutputMap.size());
 
-                    ::android::hardware::hidl_vec<Stream> streams = {
-                            inputStream, zslStream, outputStream};
-                    StreamConfiguration config = {streams,
-                            StreamConfigurationMode::NORMAL_MODE};
-                    ret = session->configureStreams(config,
+                int32_t streamId = 0;
+                for (auto &inputIter : inputOutputMap) {
+                    AvailableStream input;
+                    ASSERT_EQ(Status::OK,
+                            findLargestSize(inputStreams, inputIter.inputFormat, input));
+                    ASSERT_NE(0u, inputStreams.size());
+
+                    AvailableStream outputThreshold = {INT32_MAX, INT32_MAX,
+                            inputIter.outputFormat};
+                    std::vector<AvailableStream> outputStreams;
+                    ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+                            outputStreams, &outputThreshold));
+                    for (auto &outputIter : outputStreams) {
+                        Stream zslStream = {streamId++, StreamType::OUTPUT,
+                                static_cast<uint32_t> (input.width),
+                                static_cast<uint32_t> (input.height),
+                                static_cast<PixelFormat> (input.format),
+                                GRALLOC_USAGE_HW_CAMERA_ZSL, 0,
+                                StreamRotation::ROTATION_0};
+                        Stream inputStream = {streamId++, StreamType::INPUT,
+                                static_cast<uint32_t> (input.width),
+                                static_cast<uint32_t> (input.height),
+                                static_cast<PixelFormat> (input.format), 0, 0,
+                                StreamRotation::ROTATION_0};
+                        Stream outputStream = {streamId++, StreamType::OUTPUT,
+                                static_cast<uint32_t> (outputIter.width),
+                                static_cast<uint32_t> (outputIter.height),
+                                static_cast<PixelFormat> (outputIter.format), 0, 0,
+                                StreamRotation::ROTATION_0};
+
+                        ::android::hardware::hidl_vec<Stream> streams = {
+                                inputStream, zslStream, outputStream};
+                        StreamConfiguration config = {streams,
+                                StreamConfigurationMode::NORMAL_MODE};
+                        ret = session->configureStreams(config,
                                                     [](Status s, HalStreamConfiguration halConfig) {
                                                         ASSERT_EQ(Status::OK, s);
                                                         ASSERT_EQ(3u, halConfig.streams.size());
                                                     });
-                    ASSERT_TRUE(ret.isOk());
+                        ASSERT_TRUE(ret.isOk());
+                    }
                 }
-            }
 
-            free_camera_metadata(staticMeta);
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
+                free_camera_metadata(staticMeta);
+                ret = session->close();
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
@@ -2434,62 +2644,65 @@
 // Verify that all supported preview + still capture stream combinations
 // can be configured successfully.
 TEST_F(CameraHidlTest, configureStreamsPreviewStillOutputs) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    std::vector<AvailableStream> outputBlobStreams;
-    std::vector<AvailableStream> outputPreviewStreams;
-    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
-            static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
-    AvailableStream blobThreshold = {INT32_MAX, INT32_MAX,
-            static_cast<int32_t>(PixelFormat::BLOB)};
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        std::vector<AvailableStream> outputBlobStreams;
+        std::vector<AvailableStream> outputPreviewStreams;
+        AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+        AvailableStream blobThreshold = {INT32_MAX, INT32_MAX,
+                static_cast<int32_t>(PixelFormat::BLOB)};
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            camera_metadata_t *staticMeta;
-            Return<void> ret;
-            sp<ICameraDeviceSession> session;
-            openEmptyDeviceSession(name, env, &session /*out*/,
-                    &staticMeta /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                camera_metadata_t *staticMeta;
+                Return<void> ret;
+                sp<ICameraDeviceSession> session;
+                openEmptyDeviceSession(name, provider.second, &session /*out*/,
+                        &staticMeta /*out*/);
 
-            outputBlobStreams.clear();
-            ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
-                    outputBlobStreams, &blobThreshold));
-            ASSERT_NE(0u, outputBlobStreams.size());
+                outputBlobStreams.clear();
+                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+                        outputBlobStreams, &blobThreshold));
+                ASSERT_NE(0u, outputBlobStreams.size());
 
-            outputPreviewStreams.clear();
-            ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
-                    outputPreviewStreams, &previewThreshold));
-            ASSERT_NE(0u, outputPreviewStreams.size());
+                outputPreviewStreams.clear();
+                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+                        outputPreviewStreams, &previewThreshold));
+                ASSERT_NE(0u, outputPreviewStreams.size());
 
-            int32_t streamId = 0;
-            for (auto &blobIter : outputBlobStreams) {
-                for (auto &previewIter : outputPreviewStreams) {
-                    Stream previewStream = {streamId++, StreamType::OUTPUT,
-                            static_cast<uint32_t> (previewIter.width),
-                            static_cast<uint32_t> (previewIter.height),
-                            static_cast<PixelFormat> (previewIter.format), 0, 0,
-                            StreamRotation::ROTATION_0};
-                    Stream blobStream = {streamId++, StreamType::OUTPUT,
-                            static_cast<uint32_t> (blobIter.width),
-                            static_cast<uint32_t> (blobIter.height),
-                            static_cast<PixelFormat> (blobIter.format), 0, 0,
-                            StreamRotation::ROTATION_0};
-                    ::android::hardware::hidl_vec<Stream> streams = {
-                            previewStream, blobStream};
-                    StreamConfiguration config = {streams,
-                            StreamConfigurationMode::NORMAL_MODE};
-                    ret = session->configureStreams(config,
+                int32_t streamId = 0;
+                for (auto &blobIter : outputBlobStreams) {
+                    for (auto &previewIter : outputPreviewStreams) {
+                        Stream previewStream = {streamId++, StreamType::OUTPUT,
+                                static_cast<uint32_t> (previewIter.width),
+                                static_cast<uint32_t> (previewIter.height),
+                                static_cast<PixelFormat> (previewIter.format), 0, 0,
+                                StreamRotation::ROTATION_0};
+                        Stream blobStream = {streamId++, StreamType::OUTPUT,
+                                static_cast<uint32_t> (blobIter.width),
+                                static_cast<uint32_t> (blobIter.height),
+                                static_cast<PixelFormat> (blobIter.format), 0, 0,
+                                StreamRotation::ROTATION_0};
+                        ::android::hardware::hidl_vec<Stream> streams = {
+                                previewStream, blobStream};
+                        StreamConfiguration config = {streams,
+                                StreamConfigurationMode::NORMAL_MODE};
+                        ret = session->configureStreams(config,
                                                     [](Status s, HalStreamConfiguration halConfig) {
                                                         ASSERT_EQ(Status::OK, s);
                                                         ASSERT_EQ(2u, halConfig.streams.size());
                                                     });
-                    ASSERT_TRUE(ret.isOk());
+                        ASSERT_TRUE(ret.isOk());
+                    }
                 }
-            }
 
-            free_camera_metadata(staticMeta);
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
+                free_camera_metadata(staticMeta);
+                ret = session->close();
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
@@ -2498,89 +2711,95 @@
 // configured. Additionally check for common invalid inputs when
 // using this mode.
 TEST_F(CameraHidlTest, configureStreamsConstrainedOutputs) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            camera_metadata_t *staticMeta;
-            Return<void> ret;
-            sp<ICameraDeviceSession> session;
-            openEmptyDeviceSession(name, env, &session /*out*/,
-                    &staticMeta /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                camera_metadata_t *staticMeta;
+                Return<void> ret;
+                sp<ICameraDeviceSession> session;
+                openEmptyDeviceSession(name, provider.second, &session /*out*/,
+                        &staticMeta /*out*/);
 
-            Status rc = isConstrainedModeAvailable(staticMeta);
-            if (Status::METHOD_NOT_SUPPORTED == rc) {
+                Status rc = isConstrainedModeAvailable(staticMeta);
+                if (Status::METHOD_NOT_SUPPORTED == rc) {
+                    ret = session->close();
+                    ASSERT_TRUE(ret.isOk());
+                    continue;
+                }
+                ASSERT_EQ(Status::OK, rc);
+
+                AvailableStream hfrStream;
+                rc = pickConstrainedModeSize(staticMeta, hfrStream);
+                ASSERT_EQ(Status::OK, rc);
+
+                int32_t streamId = 0;
+                Stream stream = {streamId, StreamType::OUTPUT,
+                        static_cast<uint32_t> (hfrStream.width),
+                        static_cast<uint32_t> (hfrStream.height),
+                        static_cast<PixelFormat> (hfrStream.format), 0, 0,
+                        StreamRotation::ROTATION_0};
+                ::android::hardware::hidl_vec<Stream> streams = {stream};
+                StreamConfiguration config = {streams,
+                        StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+                ret = session->configureStreams(config, [streamId] (Status s,
+                        HalStreamConfiguration halConfig) {
+                    ASSERT_EQ(Status::OK, s);
+                    ASSERT_EQ(1u, halConfig.streams.size());
+                    ASSERT_EQ(halConfig.streams[0].id, streamId);
+                });
+                ASSERT_TRUE(ret.isOk());
+
+                stream = {streamId++, StreamType::OUTPUT,
+                        static_cast<uint32_t> (0),
+                        static_cast<uint32_t> (0),
+                        static_cast<PixelFormat> (hfrStream.format), 0, 0,
+                        StreamRotation::ROTATION_0};
+                streams[0] = stream;
+                config = {streams,
+                        StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+                ret = session->configureStreams(config, [] (Status s,
+                        HalStreamConfiguration) {
+                    ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
+                                (Status::INTERNAL_ERROR == s));
+                });
+                ASSERT_TRUE(ret.isOk());
+
+                stream = {streamId++, StreamType::OUTPUT,
+                        static_cast<uint32_t> (UINT32_MAX),
+                        static_cast<uint32_t> (UINT32_MAX),
+                        static_cast<PixelFormat> (hfrStream.format), 0, 0,
+                        StreamRotation::ROTATION_0};
+                streams[0] = stream;
+                config = {streams,
+                        StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+                ret = session->configureStreams(config, [] (Status s,
+                        HalStreamConfiguration) {
+                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                });
+                ASSERT_TRUE(ret.isOk());
+
+                stream = {streamId++, StreamType::OUTPUT,
+                        static_cast<uint32_t> (hfrStream.width),
+                        static_cast<uint32_t> (hfrStream.height),
+                        static_cast<PixelFormat> (UINT32_MAX), 0, 0,
+                        StreamRotation::ROTATION_0};
+                streams[0] = stream;
+                config = {streams,
+                        StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
+                ret = session->configureStreams(config, [] (Status s,
+                        HalStreamConfiguration) {
+                    ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
+                });
+                ASSERT_TRUE(ret.isOk());
+
+                free_camera_metadata(staticMeta);
                 ret = session->close();
                 ASSERT_TRUE(ret.isOk());
-                continue;
             }
-            ASSERT_EQ(Status::OK, rc);
-
-            AvailableStream hfrStream;
-            rc = pickConstrainedModeSize(staticMeta, hfrStream);
-            ASSERT_EQ(Status::OK, rc);
-
-            int32_t streamId = 0;
-            Stream stream = {streamId, StreamType::OUTPUT,
-                    static_cast<uint32_t> (hfrStream.width),
-                    static_cast<uint32_t> (hfrStream.height),
-                    static_cast<PixelFormat> (hfrStream.format), 0, 0,
-                    StreamRotation::ROTATION_0};
-            ::android::hardware::hidl_vec<Stream> streams = {stream};
-            StreamConfiguration config = {streams,
-                    StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-            ret = session->configureStreams(config, [streamId] (Status s,
-                    HalStreamConfiguration halConfig) {
-                ASSERT_EQ(Status::OK, s);
-                ASSERT_EQ(1u, halConfig.streams.size());
-                ASSERT_EQ(halConfig.streams[0].id, streamId);
-            });
-            ASSERT_TRUE(ret.isOk());
-
-            stream = {streamId++, StreamType::OUTPUT,
-                    static_cast<uint32_t> (0),
-                    static_cast<uint32_t> (0),
-                    static_cast<PixelFormat> (hfrStream.format), 0, 0,
-                    StreamRotation::ROTATION_0};
-            streams[0] = stream;
-            config = {streams,
-                    StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-            ret = session->configureStreams(config, [](Status s, HalStreamConfiguration) {
-                ASSERT_TRUE((Status::ILLEGAL_ARGUMENT == s) ||
-                            (Status::INTERNAL_ERROR == s));
-            });
-            ASSERT_TRUE(ret.isOk());
-
-            stream = {streamId++, StreamType::OUTPUT,
-                    static_cast<uint32_t> (UINT32_MAX),
-                    static_cast<uint32_t> (UINT32_MAX),
-                    static_cast<PixelFormat> (hfrStream.format), 0, 0,
-                    StreamRotation::ROTATION_0};
-            streams[0] = stream;
-            config = {streams,
-                    StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-            ret = session->configureStreams(config, [](Status s, HalStreamConfiguration) {
-                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-            });
-            ASSERT_TRUE(ret.isOk());
-
-            stream = {streamId++, StreamType::OUTPUT,
-                    static_cast<uint32_t> (hfrStream.width),
-                    static_cast<uint32_t> (hfrStream.height),
-                    static_cast<PixelFormat> (UINT32_MAX), 0, 0,
-                    StreamRotation::ROTATION_0};
-            streams[0] = stream;
-            config = {streams,
-                    StreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE};
-            ret = session->configureStreams(config, [](Status s, HalStreamConfiguration) {
-                ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
-            });
-            ASSERT_TRUE(ret.isOk());
-
-            free_camera_metadata(staticMeta);
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
         }
     }
 }
@@ -2588,209 +2807,215 @@
 // Verify that all supported video + snapshot stream combinations can
 // be configured successfully.
 TEST_F(CameraHidlTest, configureStreamsVideoStillOutputs) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    std::vector<AvailableStream> outputBlobStreams;
-    std::vector<AvailableStream> outputVideoStreams;
-    AvailableStream videoThreshold = {kMaxVideoWidth, kMaxVideoHeight,
-            static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
-    AvailableStream blobThreshold = {kMaxVideoWidth, kMaxVideoHeight,
-            static_cast<int32_t>(PixelFormat::BLOB)};
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        std::vector<AvailableStream> outputBlobStreams;
+        std::vector<AvailableStream> outputVideoStreams;
+        AvailableStream videoThreshold = {kMaxVideoWidth, kMaxVideoHeight,
+                static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+        AvailableStream blobThreshold = {kMaxVideoWidth, kMaxVideoHeight,
+                static_cast<int32_t>(PixelFormat::BLOB)};
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            camera_metadata_t *staticMeta;
-            Return<void> ret;
-            sp<ICameraDeviceSession> session;
-            openEmptyDeviceSession(name, env, &session /*out*/,
-                    &staticMeta /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                camera_metadata_t *staticMeta;
+                Return<void> ret;
+                sp<ICameraDeviceSession> session;
+                openEmptyDeviceSession(name, provider.second, &session /*out*/,
+                        &staticMeta /*out*/);
 
-            outputBlobStreams.clear();
-            ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
-                    outputBlobStreams, &blobThreshold));
-            ASSERT_NE(0u, outputBlobStreams.size());
+                outputBlobStreams.clear();
+                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+                        outputBlobStreams, &blobThreshold));
+                ASSERT_NE(0u, outputBlobStreams.size());
 
-            outputVideoStreams.clear();
-            ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
-                    outputVideoStreams, &videoThreshold));
-            ASSERT_NE(0u, outputVideoStreams.size());
+                outputVideoStreams.clear();
+                ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta,
+                        outputVideoStreams, &videoThreshold));
+                ASSERT_NE(0u, outputVideoStreams.size());
 
-            int32_t streamId = 0;
-            for (auto &blobIter : outputBlobStreams) {
-                for (auto &videoIter : outputVideoStreams) {
-                    Stream videoStream = {streamId++, StreamType::OUTPUT,
-                            static_cast<uint32_t> (videoIter.width),
-                            static_cast<uint32_t> (videoIter.height),
-                            static_cast<PixelFormat> (videoIter.format), 0, 0,
-                            StreamRotation::ROTATION_0};
-                    Stream blobStream = {streamId++, StreamType::OUTPUT,
-                            static_cast<uint32_t> (blobIter.width),
-                            static_cast<uint32_t> (blobIter.height),
-                            static_cast<PixelFormat> (blobIter.format),
-                            GRALLOC_USAGE_HW_VIDEO_ENCODER, 0,
-                            StreamRotation::ROTATION_0};
-                    ::android::hardware::hidl_vec<Stream> streams = {
-                            videoStream, blobStream};
-                    StreamConfiguration config = {streams,
-                            StreamConfigurationMode::NORMAL_MODE};
-                    ret = session->configureStreams(config,
+                int32_t streamId = 0;
+                for (auto &blobIter : outputBlobStreams) {
+                    for (auto &videoIter : outputVideoStreams) {
+                        Stream videoStream = {streamId++, StreamType::OUTPUT,
+                                static_cast<uint32_t> (videoIter.width),
+                                static_cast<uint32_t> (videoIter.height),
+                                static_cast<PixelFormat> (videoIter.format),
+                                0, 0, StreamRotation::ROTATION_0};
+                        Stream blobStream = {streamId++, StreamType::OUTPUT,
+                                static_cast<uint32_t> (blobIter.width),
+                                static_cast<uint32_t> (blobIter.height),
+                                static_cast<PixelFormat> (blobIter.format),
+                                GRALLOC_USAGE_HW_VIDEO_ENCODER, 0,
+                                StreamRotation::ROTATION_0};
+                        ::android::hardware::hidl_vec<Stream> streams = {
+                                videoStream, blobStream};
+                        StreamConfiguration config = {streams,
+                                StreamConfigurationMode::NORMAL_MODE};
+                        ret = session->configureStreams(config,
                                                     [](Status s, HalStreamConfiguration halConfig) {
                                                         ASSERT_EQ(Status::OK, s);
                                                         ASSERT_EQ(2u, halConfig.streams.size());
                                                     });
-                    ASSERT_TRUE(ret.isOk());
+                        ASSERT_TRUE(ret.isOk());
+                    }
                 }
-            }
 
-            free_camera_metadata(staticMeta);
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
+                free_camera_metadata(staticMeta);
+                ret = session->close();
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
 
 // Generate and verify a camera capture request
 TEST_F(CameraHidlTest, processCaptureRequestPreview) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
-            static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
-    uint64_t bufferId = 1;
-    uint32_t frameNumber = 1;
-    ::android::hardware::hidl_vec<uint8_t> settings;
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+        uint64_t bufferId = 1;
+        uint32_t frameNumber = 1;
+        ::android::hardware::hidl_vec<uint8_t> settings;
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            Stream previewStream;
-            HalStreamConfiguration halStreamConfig;
-            sp<ICameraDeviceSession> session;
-            bool supportsPartialResults = false;
-            uint32_t partialResultCount = 0;
-            configurePreviewStream(name, env, &previewThreshold,
-                    &session /*out*/, &previewStream /*out*/,
-                    &halStreamConfig /*out*/, &supportsPartialResults /*out*/,
-                    &partialResultCount/*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                Stream previewStream;
+                HalStreamConfiguration halStreamConfig;
+                sp<ICameraDeviceSession> session;
+                bool supportsPartialResults = false;
+                uint32_t partialResultCount = 0;
+                configurePreviewStream(name, provider.second, &previewThreshold,
+                        &session /*out*/, &previewStream /*out*/,
+                        &halStreamConfig /*out*/, &supportsPartialResults /*out*/,
+                        &partialResultCount/*out*/);
 
-            std::shared_ptr<ResultMetadataQueue> resultQueue;
-            auto resultQueueRet = session->getCaptureResultMetadataQueue(
-                [&resultQueue](const auto& descriptor) {
-                    resultQueue = std::make_shared<ResultMetadataQueue>(
-                            descriptor);
-                    if (!resultQueue->isValid() ||
-                            resultQueue->availableToWrite() <= 0) {
-                        ALOGE("%s: HAL returns empty result metadata fmq,"
-                                " not use it", __func__);
-                        resultQueue = nullptr;
-                        // Don't use the queue onwards.
+                std::shared_ptr<ResultMetadataQueue> resultQueue;
+                auto resultQueueRet = session->getCaptureResultMetadataQueue(
+                    [&resultQueue](const auto& descriptor) {
+                        resultQueue = std::make_shared<ResultMetadataQueue>(
+                                descriptor);
+                        if (!resultQueue->isValid() ||
+                                resultQueue->availableToWrite() <= 0) {
+                            ALOGE("%s: HAL returns empty result metadata fmq,"
+                                    " not use it", __func__);
+                            resultQueue = nullptr;
+                            // Don't use the queue onwards.
+                        }
+                    });
+                ASSERT_TRUE(resultQueueRet.isOk());
+                ASSERT_NE(nullptr, resultQueue);
+
+                InFlightRequest inflightReq = {1, false, supportsPartialResults,
+                        partialResultCount, resultQueue};
+
+                RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+                Return<void> ret;
+                ret = session->constructDefaultRequestSettings(reqTemplate,
+                    [&](auto status, const auto& req) {
+                        ASSERT_EQ(Status::OK, status);
+                        settings = req; });
+                ASSERT_TRUE(ret.isOk());
+
+                sp<GraphicBuffer> gb = new GraphicBuffer(
+                    previewStream.width, previewStream.height,
+                    static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat),
+                    1, android_convertGralloc1To0Usage(
+                           halStreamConfig.streams[0].producerUsage,
+                           halStreamConfig.streams[0].consumerUsage));
+                ASSERT_NE(nullptr, gb.get());
+                StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+                        bufferId, hidl_handle(gb->getNativeBuffer()->handle),
+                        BufferStatus::OK, nullptr, nullptr};
+                ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
+                        outputBuffer};
+                StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+                        BufferStatus::ERROR, nullptr, nullptr};
+                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */,
+                        settings, emptyInputBuffer, outputBuffers};
+
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    mInflightMap.clear();
+                    mInflightMap.add(frameNumber, &inflightReq);
+                }
+
+                Status status = Status::INTERNAL_ERROR;
+                uint32_t numRequestProcessed = 0;
+                hidl_vec<BufferCache> cachesToRemove;
+                Return<void> returnStatus = session->processCaptureRequest(
+                        {request},
+                        cachesToRemove,
+                        [&status, &numRequestProcessed] (auto s, uint32_t n) {
+                            status = s;
+                            numRequestProcessed = n;
+                        });
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, status);
+                ASSERT_EQ(numRequestProcessed, 1u);
+
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    while (!inflightReq.errorCodeValid &&
+                            ((0 < inflightReq.numBuffersLeft) ||
+                                    (!inflightReq.haveResultMetadata))) {
+                        auto timeout = std::chrono::system_clock::now() +
+                                std::chrono::seconds(kStreamBufferTimeoutSec);
+                        ASSERT_NE(std::cv_status::timeout,
+                                mResultCondition.wait_until(l, timeout));
                     }
-                });
-            ASSERT_TRUE(resultQueueRet.isOk());
-            ASSERT_NE(nullptr, resultQueue);
 
-            InFlightRequest inflightReq = {1, false, supportsPartialResults,
-                    partialResultCount, resultQueue};
+                    ASSERT_FALSE(inflightReq.errorCodeValid);
+                    ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+                    ASSERT_EQ(previewStream.id,
+                              inflightReq.resultOutputBuffers[0].streamId);
 
-            RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
-            Return<void> ret;
-            ret = session->constructDefaultRequestSettings(reqTemplate,
-                [&](auto status, const auto& req) {
-                    ASSERT_EQ(Status::OK, status);
-                    settings = req; });
-            ASSERT_TRUE(ret.isOk());
-
-            sp<GraphicBuffer> gb = new GraphicBuffer(
-                previewStream.width, previewStream.height,
-                static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat),
-                1, android_convertGralloc1To0Usage(
-                       halStreamConfig.streams[0].producerUsage,
-                       halStreamConfig.streams[0].consumerUsage));
-            ASSERT_NE(nullptr, gb.get());
-            StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
-                    bufferId, hidl_handle(gb->getNativeBuffer()->handle),
-                    BufferStatus::OK, nullptr, nullptr};
-            ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
-                    outputBuffer};
-            StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
-                    BufferStatus::ERROR, nullptr, nullptr};
-            CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                    emptyInputBuffer, outputBuffers};
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                mInflightMap.clear();
-                mInflightMap.add(frameNumber, &inflightReq);
-            }
-
-            Status status = Status::INTERNAL_ERROR;
-            uint32_t numRequestProcessed = 0;
-            hidl_vec<BufferCache> cachesToRemove;
-            Return<void> returnStatus = session->processCaptureRequest(
-                    {request},
-                    cachesToRemove,
-                    [&status, &numRequestProcessed] (auto s, uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, status);
-            ASSERT_EQ(numRequestProcessed, 1u);
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                while (!inflightReq.errorCodeValid &&
-                        ((0 < inflightReq.numBuffersLeft) ||
-                                (!inflightReq.haveResultMetadata))) {
-                    auto timeout = std::chrono::system_clock::now() +
-                            std::chrono::seconds(kStreamBufferTimeoutSec);
-                    ASSERT_NE(std::cv_status::timeout,
-                            mResultCondition.wait_until(l, timeout));
+                    request.frameNumber++;
+                    //Empty settings should be supported after the first call
+                    //for repeating requests.
+                    request.settings.setToExternal(nullptr, 0, true);
+                    mInflightMap.clear();
+                    inflightReq = {1, false, supportsPartialResults,
+                                        partialResultCount, resultQueue};
+                    mInflightMap.add(request.frameNumber, &inflightReq);
                 }
 
-                ASSERT_FALSE(inflightReq.errorCodeValid);
-                ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                ASSERT_EQ(previewStream.id,
-                          inflightReq.resultOutputBuffers[0].streamId);
+                returnStatus = session->processCaptureRequest(
+                        {request},
+                        cachesToRemove,
+                        [&status, &numRequestProcessed] (auto s, uint32_t n) {
+                            status = s;
+                            numRequestProcessed = n;
+                        });
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, status);
+                ASSERT_EQ(numRequestProcessed, 1u);
 
-                request.frameNumber++;
-                //Empty settings should be supported after the first call
-                //for repeating requests.
-                request.settings.setToExternal(nullptr, 0, true);
-                mInflightMap.clear();
-                inflightReq = {1, false, supportsPartialResults,
-                                    partialResultCount, resultQueue};
-                mInflightMap.add(request.frameNumber, &inflightReq);
-            }
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    while (!inflightReq.errorCodeValid &&
+                            ((0 < inflightReq.numBuffersLeft) ||
+                                    (!inflightReq.haveResultMetadata))) {
+                        auto timeout = std::chrono::system_clock::now() +
+                                std::chrono::seconds(kStreamBufferTimeoutSec);
+                        ASSERT_NE(std::cv_status::timeout,
+                                mResultCondition.wait_until(l, timeout));
+                    }
 
-            returnStatus = session->processCaptureRequest(
-                    {request},
-                    cachesToRemove,
-                    [&status, &numRequestProcessed] (auto s, uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, status);
-            ASSERT_EQ(numRequestProcessed, 1u);
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                while (!inflightReq.errorCodeValid &&
-                        ((0 < inflightReq.numBuffersLeft) ||
-                                (!inflightReq.haveResultMetadata))) {
-                    auto timeout = std::chrono::system_clock::now() +
-                            std::chrono::seconds(kStreamBufferTimeoutSec);
-                    ASSERT_NE(std::cv_status::timeout,
-                            mResultCondition.wait_until(l, timeout));
+                    ASSERT_FALSE(inflightReq.errorCodeValid);
+                    ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+                    ASSERT_EQ(previewStream.id,
+                              inflightReq.resultOutputBuffers[0].streamId);
                 }
 
-                ASSERT_FALSE(inflightReq.errorCodeValid);
-                ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                ASSERT_EQ(previewStream.id,
-                          inflightReq.resultOutputBuffers[0].streamId);
+                ret = session->close();
+                ASSERT_TRUE(ret.isOk());
             }
-
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
         }
     }
 }
@@ -2798,61 +3023,64 @@
 // Test whether an incorrect capture request with missing settings will
 // be reported correctly.
 TEST_F(CameraHidlTest, processCaptureRequestInvalidSinglePreview) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    std::vector<AvailableStream> outputPreviewStreams;
-    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
-            static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
-    uint64_t bufferId = 1;
-    uint32_t frameNumber = 1;
-    ::android::hardware::hidl_vec<uint8_t> settings;
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        std::vector<AvailableStream> outputPreviewStreams;
+        AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+        uint64_t bufferId = 1;
+        uint32_t frameNumber = 1;
+        ::android::hardware::hidl_vec<uint8_t> settings;
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            Stream previewStream;
-            HalStreamConfiguration halStreamConfig;
-            sp<ICameraDeviceSession> session;
-            bool supportsPartialResults = false;
-            uint32_t partialResultCount = 0;
-            configurePreviewStream(name, env, &previewThreshold,
-                    &session /*out*/, &previewStream /*out*/,
-                    &halStreamConfig /*out*/, &supportsPartialResults /*out*/,
-                    &partialResultCount /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                Stream previewStream;
+                HalStreamConfiguration halStreamConfig;
+                sp<ICameraDeviceSession> session;
+                bool supportsPartialResults = false;
+                uint32_t partialResultCount = 0;
+                configurePreviewStream(name, provider.second, &previewThreshold,
+                        &session /*out*/, &previewStream /*out*/,
+                        &halStreamConfig /*out*/, &supportsPartialResults /*out*/,
+                        &partialResultCount /*out*/);
 
-            sp<GraphicBuffer> gb = new GraphicBuffer(
-                previewStream.width, previewStream.height,
-                static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat),
-                1, android_convertGralloc1To0Usage(
-                       halStreamConfig.streams[0].producerUsage,
-                       halStreamConfig.streams[0].consumerUsage));
+                sp<GraphicBuffer> gb = new GraphicBuffer(
+                    previewStream.width, previewStream.height,
+                    static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat),
+                    1, android_convertGralloc1To0Usage(
+                           halStreamConfig.streams[0].producerUsage,
+                           halStreamConfig.streams[0].consumerUsage));
 
-            StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
-                    bufferId, hidl_handle(gb->getNativeBuffer()->handle),
-                    BufferStatus::OK, nullptr, nullptr};
-            ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
-                    outputBuffer};
-            StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
-                    BufferStatus::ERROR, nullptr, nullptr};
-            CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                    emptyInputBuffer, outputBuffers};
+                StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+                        bufferId, hidl_handle(gb->getNativeBuffer()->handle),
+                        BufferStatus::OK, nullptr, nullptr};
+                ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
+                        outputBuffer};
+                StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+                        BufferStatus::ERROR, nullptr, nullptr};
+                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
+                        emptyInputBuffer, outputBuffers};
 
-            //Settings were not correctly initialized, we should fail here
-            Status status = Status::OK;
-            uint32_t numRequestProcessed = 0;
-            hidl_vec<BufferCache> cachesToRemove;
-            Return<void> ret = session->processCaptureRequest(
-                    {request},
-                    cachesToRemove,
-                    [&status, &numRequestProcessed] (auto s, uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-            ASSERT_TRUE(ret.isOk());
-            ASSERT_EQ(Status::INTERNAL_ERROR, status);
-            ASSERT_EQ(numRequestProcessed, 0u);
+                //Settings were not correctly initialized, we should fail here
+                Status status = Status::OK;
+                uint32_t numRequestProcessed = 0;
+                hidl_vec<BufferCache> cachesToRemove;
+                Return<void> ret = session->processCaptureRequest(
+                        {request},
+                        cachesToRemove,
+                        [&status, &numRequestProcessed] (auto s, uint32_t n) {
+                            status = s;
+                            numRequestProcessed = n;
+                        });
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(Status::INTERNAL_ERROR, status);
+                ASSERT_EQ(numRequestProcessed, 0u);
 
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
+                ret = session->close();
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
@@ -2860,222 +3088,231 @@
 // Check whether an invalid capture request with missing output buffers
 // will be reported correctly.
 TEST_F(CameraHidlTest, processCaptureRequestInvalidBuffer) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    std::vector<AvailableStream> outputBlobStreams;
-    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
-            static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
-    uint32_t frameNumber = 1;
-    ::android::hardware::hidl_vec<uint8_t> settings;
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        std::vector<AvailableStream> outputBlobStreams;
+        AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+        uint32_t frameNumber = 1;
+        ::android::hardware::hidl_vec<uint8_t> settings;
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            Stream previewStream;
-            HalStreamConfiguration halStreamConfig;
-            sp<ICameraDeviceSession> session;
-            bool supportsPartialResults = false;
-            uint32_t partialResultCount = 0;
-            configurePreviewStream(name, env, &previewThreshold,
-                    &session /*out*/, &previewStream /*out*/,
-                    &halStreamConfig /*out*/, &supportsPartialResults/*out*/,
-                    &partialResultCount /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                Stream previewStream;
+                HalStreamConfiguration halStreamConfig;
+                sp<ICameraDeviceSession> session;
+                bool supportsPartialResults = false;
+                uint32_t partialResultCount = 0;
+                configurePreviewStream(name, provider.second, &previewThreshold,
+                        &session /*out*/, &previewStream /*out*/,
+                        &halStreamConfig /*out*/, &supportsPartialResults/*out*/,
+                        &partialResultCount /*out*/);
 
-            RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
-            Return<void> ret;
-            ret = session->constructDefaultRequestSettings(reqTemplate,
-                [&](auto status, const auto& req) {
-                    ASSERT_EQ(Status::OK, status);
-                    settings = req; });
-            ASSERT_TRUE(ret.isOk());
+                RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+                Return<void> ret;
+                ret = session->constructDefaultRequestSettings(reqTemplate,
+                    [&](auto status, const auto& req) {
+                        ASSERT_EQ(Status::OK, status);
+                        settings = req; });
+                ASSERT_TRUE(ret.isOk());
 
-            ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers;
-            StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
-                    BufferStatus::ERROR, nullptr, nullptr};
-            CaptureRequest request = {frameNumber, 0/* fmqSettingsSize */, settings,
-                    emptyInputBuffer, emptyOutputBuffers};
+                ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers;
+                StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+                        BufferStatus::ERROR, nullptr, nullptr};
+                CaptureRequest request = {frameNumber, 0/* fmqSettingsSize */,
+                        settings, emptyInputBuffer, emptyOutputBuffers};
 
-            //Output buffers are missing, we should fail here
-            Status status = Status::OK;
-            uint32_t numRequestProcessed = 0;
-            hidl_vec<BufferCache> cachesToRemove;
-            ret = session->processCaptureRequest(
-                    {request},
-                    cachesToRemove,
-                    [&status, &numRequestProcessed] (auto s, uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
-                    });
-            ASSERT_TRUE(ret.isOk());
-            ASSERT_EQ(Status::INTERNAL_ERROR, status);
-            ASSERT_EQ(numRequestProcessed, 0u);
+                //Output buffers are missing, we should fail here
+                Status status = Status::OK;
+                uint32_t numRequestProcessed = 0;
+                hidl_vec<BufferCache> cachesToRemove;
+                ret = session->processCaptureRequest(
+                        {request},
+                        cachesToRemove,
+                        [&status, &numRequestProcessed] (auto s, uint32_t n) {
+                            status = s;
+                            numRequestProcessed = n;
+                        });
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(Status::INTERNAL_ERROR, status);
+                ASSERT_EQ(numRequestProcessed, 0u);
 
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
+                ret = session->close();
+                ASSERT_TRUE(ret.isOk());
+            }
         }
     }
 }
 
 // Generate, trigger and flush a preview request
 TEST_F(CameraHidlTest, flushPreviewRequest) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    std::vector<AvailableStream> outputPreviewStreams;
-    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
-            static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
-    uint64_t bufferId = 1;
-    uint32_t frameNumber = 1;
-    ::android::hardware::hidl_vec<uint8_t> settings;
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        std::vector<AvailableStream> outputPreviewStreams;
+        AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+        uint64_t bufferId = 1;
+        uint32_t frameNumber = 1;
+        ::android::hardware::hidl_vec<uint8_t> settings;
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            Stream previewStream;
-            HalStreamConfiguration halStreamConfig;
-            sp<ICameraDeviceSession> session;
-            bool supportsPartialResults = false;
-            uint32_t partialResultCount = 0;
-            configurePreviewStream(name, env, &previewThreshold,
-                    &session /*out*/, &previewStream /*out*/,
-                    &halStreamConfig /*out*/, &supportsPartialResults /*out*/,
-                    &partialResultCount /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                Stream previewStream;
+                HalStreamConfiguration halStreamConfig;
+                sp<ICameraDeviceSession> session;
+                bool supportsPartialResults = false;
+                uint32_t partialResultCount = 0;
+                configurePreviewStream(name, provider.second, &previewThreshold,
+                        &session /*out*/, &previewStream /*out*/,
+                        &halStreamConfig /*out*/, &supportsPartialResults /*out*/,
+                        &partialResultCount /*out*/);
 
-            std::shared_ptr<ResultMetadataQueue> resultQueue;
-            auto resultQueueRet = session->getCaptureResultMetadataQueue(
-                [&resultQueue](const auto& descriptor) {
-                    resultQueue = std::make_shared<ResultMetadataQueue>(
-                            descriptor);
-                    if (!resultQueue->isValid() ||
-                            resultQueue->availableToWrite() <= 0) {
-                        ALOGE("%s: HAL returns empty result metadata fmq,"
-                                " not use it", __func__);
-                        resultQueue = nullptr;
-                        // Don't use the queue onwards.
-                    }
-                });
-            ASSERT_TRUE(resultQueueRet.isOk());
-            ASSERT_NE(nullptr, resultQueue);
-
-            InFlightRequest inflightReq = {1, false, supportsPartialResults,
-                    partialResultCount, resultQueue};
-            RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
-            Return<void> ret;
-            ret = session->constructDefaultRequestSettings(reqTemplate,
-                [&](auto status, const auto& req) {
-                    ASSERT_EQ(Status::OK, status);
-                    settings = req; });
-            ASSERT_TRUE(ret.isOk());
-
-            sp<GraphicBuffer> gb = new GraphicBuffer(
-                previewStream.width, previewStream.height,
-                static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat),
-                1, android_convertGralloc1To0Usage(
-                       halStreamConfig.streams[0].producerUsage,
-                       halStreamConfig.streams[0].consumerUsage));
-            ASSERT_NE(nullptr, gb.get());
-            StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
-                    bufferId, hidl_handle(gb->getNativeBuffer()->handle),
-                    BufferStatus::OK, nullptr, nullptr};
-            ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
-                    outputBuffer};
-            const StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
-                    BufferStatus::ERROR, nullptr, nullptr};
-            CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings,
-                    emptyInputBuffer, outputBuffers};
-
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                mInflightMap.clear();
-                mInflightMap.add(frameNumber, &inflightReq);
-            }
-
-            Status status = Status::INTERNAL_ERROR;
-            uint32_t numRequestProcessed = 0;
-            hidl_vec<BufferCache> cachesToRemove;
-            ret = session->processCaptureRequest(
-                    {request},
-                    cachesToRemove,
-                    [&status, &numRequestProcessed] (auto s, uint32_t n) {
-                        status = s;
-                        numRequestProcessed = n;
+                std::shared_ptr<ResultMetadataQueue> resultQueue;
+                auto resultQueueRet = session->getCaptureResultMetadataQueue(
+                    [&resultQueue](const auto& descriptor) {
+                        resultQueue = std::make_shared<ResultMetadataQueue>(
+                                descriptor);
+                        if (!resultQueue->isValid() ||
+                                resultQueue->availableToWrite() <= 0) {
+                            ALOGE("%s: HAL returns empty result metadata fmq,"
+                                    " not use it", __func__);
+                            resultQueue = nullptr;
+                            // Don't use the queue onwards.
+                        }
                     });
+                ASSERT_TRUE(resultQueueRet.isOk());
+                ASSERT_NE(nullptr, resultQueue);
 
-            ASSERT_TRUE(ret.isOk());
-            ASSERT_EQ(Status::OK, status);
-            ASSERT_EQ(numRequestProcessed, 1u);
-            //Flush before waiting for request to complete.
-            Return<Status> returnStatus = session->flush();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
+                InFlightRequest inflightReq = {1, false, supportsPartialResults,
+                        partialResultCount, resultQueue};
+                RequestTemplate reqTemplate = RequestTemplate::PREVIEW;
+                Return<void> ret;
+                ret = session->constructDefaultRequestSettings(reqTemplate,
+                    [&](auto status, const auto& req) {
+                        ASSERT_EQ(Status::OK, status);
+                        settings = req; });
+                ASSERT_TRUE(ret.isOk());
 
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                while (!inflightReq.errorCodeValid &&
-                        ((0 < inflightReq.numBuffersLeft) ||
-                                (!inflightReq.haveResultMetadata))) {
-                    auto timeout = std::chrono::system_clock::now() +
-                            std::chrono::seconds(kStreamBufferTimeoutSec);
-                    ASSERT_NE(std::cv_status::timeout,
-                            mResultCondition.wait_until(l, timeout));
+                sp<GraphicBuffer> gb = new GraphicBuffer(
+                    previewStream.width, previewStream.height,
+                    static_cast<int32_t>(halStreamConfig.streams[0].overrideFormat),
+                    1, android_convertGralloc1To0Usage(
+                           halStreamConfig.streams[0].producerUsage,
+                           halStreamConfig.streams[0].consumerUsage));
+                ASSERT_NE(nullptr, gb.get());
+                StreamBuffer outputBuffer = {halStreamConfig.streams[0].id,
+                        bufferId, hidl_handle(gb->getNativeBuffer()->handle),
+                        BufferStatus::OK, nullptr, nullptr};
+                ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {
+                        outputBuffer};
+                const StreamBuffer emptyInputBuffer = {-1, 0, nullptr,
+                        BufferStatus::ERROR, nullptr, nullptr};
+                CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */,
+                        settings, emptyInputBuffer, outputBuffers};
+
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    mInflightMap.clear();
+                    mInflightMap.add(frameNumber, &inflightReq);
                 }
 
-                if (!inflightReq.errorCodeValid) {
-                    ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
-                    ASSERT_EQ(previewStream.id,
-                              inflightReq.resultOutputBuffers[0].streamId);
-                } else {
-                    switch (inflightReq.errorCode) {
-                        case ErrorCode::ERROR_REQUEST:
-                        case ErrorCode::ERROR_RESULT:
-                        case ErrorCode::ERROR_BUFFER:
-                            //Expected
-                            break;
-                        case ErrorCode::ERROR_DEVICE:
-                        default:
-                            FAIL() << "Unexpected error:" << static_cast<uint32_t> (
-                                    inflightReq.errorCode);
+                Status status = Status::INTERNAL_ERROR;
+                uint32_t numRequestProcessed = 0;
+                hidl_vec<BufferCache> cachesToRemove;
+                ret = session->processCaptureRequest(
+                        {request},
+                        cachesToRemove,
+                        [&status, &numRequestProcessed] (auto s, uint32_t n) {
+                            status = s;
+                            numRequestProcessed = n;
+                        });
+
+                ASSERT_TRUE(ret.isOk());
+                ASSERT_EQ(Status::OK, status);
+                ASSERT_EQ(numRequestProcessed, 1u);
+                //Flush before waiting for request to complete.
+                Return<Status> returnStatus = session->flush();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
+
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    while (!inflightReq.errorCodeValid &&
+                            ((0 < inflightReq.numBuffersLeft) ||
+                                    (!inflightReq.haveResultMetadata))) {
+                        auto timeout = std::chrono::system_clock::now() +
+                                std::chrono::seconds(kStreamBufferTimeoutSec);
+                        ASSERT_NE(std::cv_status::timeout,
+                                mResultCondition.wait_until(l, timeout));
                     }
+
+                    if (!inflightReq.errorCodeValid) {
+                        ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
+                        ASSERT_EQ(previewStream.id,
+                                  inflightReq.resultOutputBuffers[0].streamId);
+                    } else {
+                        switch (inflightReq.errorCode) {
+                            case ErrorCode::ERROR_REQUEST:
+                            case ErrorCode::ERROR_RESULT:
+                            case ErrorCode::ERROR_BUFFER:
+                                //Expected
+                                break;
+                            case ErrorCode::ERROR_DEVICE:
+                            default:
+                                FAIL() << "Unexpected error:" << static_cast<uint32_t> (
+                                        inflightReq.errorCode);
+                        }
+                    }
+
+                    ret = session->close();
+                    ASSERT_TRUE(ret.isOk());
                 }
             }
-
-            ret = session->close();
-            ASSERT_TRUE(ret.isOk());
         }
     }
 }
 
 // Verify that camera flushes correctly without any pending requests.
 TEST_F(CameraHidlTest, flushEmpty) {
-    CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
-    hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
-    std::vector<AvailableStream> outputPreviewStreams;
-    AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
-            static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+    for (auto provider : CameraHidlEnvironment::Instance()->mProviders) {
+        hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(
+                provider.second);
+        std::vector<AvailableStream> outputPreviewStreams;
+        AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+                static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
 
-    for (const auto& name : cameraDeviceNames) {
-        if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
-            Stream previewStream;
-            HalStreamConfiguration halStreamConfig;
-            sp<ICameraDeviceSession> session;
-            bool supportsPartialResults = false;
-            uint32_t partialResultCount = 0;
-            configurePreviewStream(name, env, &previewThreshold,
-                    &session /*out*/, &previewStream /*out*/,
-                    &halStreamConfig /*out*/, &supportsPartialResults /*out*/,
-                    &partialResultCount /*out*/);
+        for (const auto& name : cameraDeviceNames) {
+            if (getCameraDeviceVersion(name, provider.first) ==
+                    CAMERA_DEVICE_API_VERSION_3_2) {
+                Stream previewStream;
+                HalStreamConfiguration halStreamConfig;
+                sp<ICameraDeviceSession> session;
+                bool supportsPartialResults = false;
+                uint32_t partialResultCount = 0;
+                configurePreviewStream(name, provider.second, &previewThreshold,
+                        &session /*out*/, &previewStream /*out*/,
+                        &halStreamConfig /*out*/, &supportsPartialResults /*out*/,
+                        &partialResultCount /*out*/);
 
-            Return<Status> returnStatus = session->flush();
-            ASSERT_TRUE(returnStatus.isOk());
-            ASSERT_EQ(Status::OK, returnStatus);
+                Return<Status> returnStatus = session->flush();
+                ASSERT_TRUE(returnStatus.isOk());
+                ASSERT_EQ(Status::OK, returnStatus);
 
-            {
-                std::unique_lock<std::mutex> l(mLock);
-                auto timeout = std::chrono::system_clock::now() +
-                        std::chrono::milliseconds(kEmptyFlushTimeoutMSec);
-                ASSERT_EQ(std::cv_status::timeout,
-                        mResultCondition.wait_until(l, timeout));
+                {
+                    std::unique_lock<std::mutex> l(mLock);
+                    auto timeout = std::chrono::system_clock::now() +
+                            std::chrono::milliseconds(kEmptyFlushTimeoutMSec);
+                    ASSERT_EQ(std::cv_status::timeout,
+                            mResultCondition.wait_until(l, timeout));
+                }
+
+                Return<void> ret = session->close();
+                ASSERT_TRUE(ret.isOk());
             }
-
-            Return<void> ret = session->close();
-            ASSERT_TRUE(ret.isOk());
         }
     }
 }
@@ -3265,14 +3502,13 @@
 
 // Open a device session and configure a preview stream.
 void CameraHidlTest::configurePreviewStream(const std::string &name,
-        const CameraHidlEnvironment* env,
+        sp<ICameraProvider> provider,
         const AvailableStream *previewThreshold,
         sp<ICameraDeviceSession> *session /*out*/,
         Stream *previewStream /*out*/,
         HalStreamConfiguration *halStreamConfig /*out*/,
         bool *supportsPartialResults /*out*/,
         uint32_t *partialResultCount /*out*/) {
-    ASSERT_NE(nullptr, env);
     ASSERT_NE(nullptr, session);
     ASSERT_NE(nullptr, previewStream);
     ASSERT_NE(nullptr, halStreamConfig);
@@ -3283,7 +3519,7 @@
     ::android::sp<ICameraDevice> device3_2;
     ALOGI("configureStreams: Testing camera device %s", name.c_str());
     Return<void> ret;
-    ret = env->mProvider->getCameraDeviceInterface_V3_x(
+    ret = provider->getCameraDeviceInterface_V3_x(
         name,
         [&](auto status, const auto& device) {
             ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
@@ -3349,17 +3585,16 @@
 
 // Open a device session with empty callbacks and return static metadata.
 void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
-        const CameraHidlEnvironment* env,
+        sp<ICameraProvider> provider,
         sp<ICameraDeviceSession> *session /*out*/,
         camera_metadata_t **staticMeta /*out*/) {
-    ASSERT_NE(nullptr, env);
     ASSERT_NE(nullptr, session);
     ASSERT_NE(nullptr, staticMeta);
 
     ::android::sp<ICameraDevice> device3_2;
     ALOGI("configureStreams: Testing camera device %s", name.c_str());
     Return<void> ret;
-    ret = env->mProvider->getCameraDeviceInterface_V3_x(
+    ret = provider->getCameraDeviceInterface_V3_x(
         name,
         [&](auto status, const auto& device) {
             ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
@@ -3391,13 +3626,12 @@
 
 // Open a particular camera device.
 void CameraHidlTest::openCameraDevice(const std::string &name,
-        const CameraHidlEnvironment* env,
+        sp<ICameraProvider> provider,
         sp<::android::hardware::camera::device::V1_0::ICameraDevice> *device1 /*out*/) {
-    ASSERT_TRUE(nullptr != env);
     ASSERT_TRUE(nullptr != device1);
 
     Return<void> ret;
-    ret = env->mProvider->getCameraDeviceInterface_V1_x(
+    ret = provider->getCameraDeviceInterface_V1_x(
             name,
             [&](auto status, const auto& device) {
             ALOGI("getCameraDeviceInterface_V1_x returns status:%d",
diff --git a/cas/1.0/Android.bp b/cas/1.0/Android.bp
new file mode 100644
index 0000000..2251f11
--- /dev/null
+++ b/cas/1.0/Android.bp
@@ -0,0 +1,84 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+    name: "android.hardware.cas@1.0_hal",
+    srcs: [
+        "types.hal",
+        "ICas.hal",
+        "ICasListener.hal",
+        "IDescramblerBase.hal",
+        "IMediaCasService.hal",
+    ],
+}
+
+genrule {
+    name: "android.hardware.cas@1.0_genc++",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas@1.0",
+    srcs: [
+        ":android.hardware.cas@1.0_hal",
+    ],
+    out: [
+        "android/hardware/cas/1.0/types.cpp",
+        "android/hardware/cas/1.0/CasAll.cpp",
+        "android/hardware/cas/1.0/CasListenerAll.cpp",
+        "android/hardware/cas/1.0/DescramblerBaseAll.cpp",
+        "android/hardware/cas/1.0/MediaCasServiceAll.cpp",
+    ],
+}
+
+genrule {
+    name: "android.hardware.cas@1.0_genc++_headers",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas@1.0",
+    srcs: [
+        ":android.hardware.cas@1.0_hal",
+    ],
+    out: [
+        "android/hardware/cas/1.0/types.h",
+        "android/hardware/cas/1.0/hwtypes.h",
+        "android/hardware/cas/1.0/ICas.h",
+        "android/hardware/cas/1.0/IHwCas.h",
+        "android/hardware/cas/1.0/BnHwCas.h",
+        "android/hardware/cas/1.0/BpHwCas.h",
+        "android/hardware/cas/1.0/BsCas.h",
+        "android/hardware/cas/1.0/ICasListener.h",
+        "android/hardware/cas/1.0/IHwCasListener.h",
+        "android/hardware/cas/1.0/BnHwCasListener.h",
+        "android/hardware/cas/1.0/BpHwCasListener.h",
+        "android/hardware/cas/1.0/BsCasListener.h",
+        "android/hardware/cas/1.0/IDescramblerBase.h",
+        "android/hardware/cas/1.0/IHwDescramblerBase.h",
+        "android/hardware/cas/1.0/BnHwDescramblerBase.h",
+        "android/hardware/cas/1.0/BpHwDescramblerBase.h",
+        "android/hardware/cas/1.0/BsDescramblerBase.h",
+        "android/hardware/cas/1.0/IMediaCasService.h",
+        "android/hardware/cas/1.0/IHwMediaCasService.h",
+        "android/hardware/cas/1.0/BnHwMediaCasService.h",
+        "android/hardware/cas/1.0/BpHwMediaCasService.h",
+        "android/hardware/cas/1.0/BsMediaCasService.h",
+    ],
+}
+
+cc_library_shared {
+    name: "android.hardware.cas@1.0",
+    defaults: ["hidl-module-defaults"],
+    generated_sources: ["android.hardware.cas@1.0_genc++"],
+    generated_headers: ["android.hardware.cas@1.0_genc++_headers"],
+    export_generated_headers: ["android.hardware.cas@1.0_genc++_headers"],
+    vendor_available: true,
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libutils",
+        "libcutils",
+    ],
+    export_shared_lib_headers: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+    ],
+}
diff --git a/cas/1.0/CasHal.mk b/cas/1.0/CasHal.mk
new file mode 100644
index 0000000..3cae6bf
--- /dev/null
+++ b/cas/1.0/CasHal.mk
@@ -0,0 +1,192 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+########################################################################
+# Included by frameworks/base for MediaCas. Hidl HAL can't be linked as
+# Java lib from frameworks because it has dependency on frameworks itself.
+#
+
+intermediates := $(TARGET_OUT_COMMON_GEN)/JAVA_LIBRARIES/android.hardware.cas-V1.0-java_intermediates
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+HIDL_PATH := system/libhidl/transport/base/1.0
+
+#
+# Build types.hal (DebugInfo)
+#
+GEN := $(intermediates)/android/hidl/base/V1_0/DebugInfo.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hidl:system/libhidl/transport \
+        android.hidl.base@1.0::types.DebugInfo
+
+$(GEN): $(HIDL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IBase.hal
+#
+GEN := $(intermediates)/android/hidl/base/V1_0/IBase.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IBase.hal
+$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal
+$(GEN): $(HIDL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hidl:system/libhidl/transport \
+        android.hidl.base@1.0::IBase
+
+$(GEN): $(HIDL_PATH)/IBase.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+HIDL_PATH := hardware/interfaces/cas/1.0
+
+#
+# Build types.hal (HidlCasPluginDescriptor)
+#
+GEN := $(intermediates)/android/hardware/cas/V1_0/HidlCasPluginDescriptor.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.cas@1.0::types.HidlCasPluginDescriptor
+
+$(GEN): $(HIDL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (Status)
+#
+GEN := $(intermediates)/android/hardware/cas/V1_0/Status.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.cas@1.0::types.Status
+
+$(GEN): $(HIDL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build ICas.hal
+#
+GEN := $(intermediates)/android/hardware/cas/V1_0/ICas.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/ICas.hal
+$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal
+$(GEN): $(HIDL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.cas@1.0::ICas
+
+$(GEN): $(HIDL_PATH)/ICas.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build ICasListener.hal
+#
+GEN := $(intermediates)/android/hardware/cas/V1_0/ICasListener.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/ICasListener.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.cas@1.0::ICasListener
+
+$(GEN): $(HIDL_PATH)/ICasListener.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IDescramblerBase.hal
+#
+GEN := $(intermediates)/android/hardware/cas/V1_0/IDescramblerBase.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IDescramblerBase.hal
+$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal
+$(GEN): $(HIDL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.cas@1.0::IDescramblerBase
+
+$(GEN): $(HIDL_PATH)/IDescramblerBase.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IMediaCasService.hal
+#
+GEN := $(intermediates)/android/hardware/cas/V1_0/IMediaCasService.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(HIDL_PATH)/IMediaCasService.hal
+$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/ICas.hal
+$(GEN): $(HIDL_PATH)/ICas.hal
+$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/ICasListener.hal
+$(GEN): $(HIDL_PATH)/ICasListener.hal
+$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/IDescramblerBase.hal
+$(GEN): $(HIDL_PATH)/IDescramblerBase.hal
+$(GEN): PRIVATE_DEPS += $(HIDL_PATH)/types.hal
+$(GEN): $(HIDL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.cas@1.0::IMediaCasService
+
+$(GEN): $(HIDL_PATH)/IMediaCasService.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
diff --git a/cas/1.0/ICas.hal b/cas/1.0/ICas.hal
new file mode 100644
index 0000000..08a92da
--- /dev/null
+++ b/cas/1.0/ICas.hal
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.cas@1.0;
+
+import android.hardware.cas@1.0::types;
+
+/**
+  * ICas is the API to control the cas system and is accessible from both
+ * Java and native level. It is used to manage sessions, provision/refresh
+ * the cas system, and process the EMM/ECM messages. It also allows bi-directional,
+ * scheme-specific communications between the client and the cas system.
+ */
+
+interface ICas {
+    /**
+     * Provide the CA private data from a CA_descriptor in the conditional
+     * access table to a CasPlugin.
+     *
+     * @param pvtData a byte array containing the private data, the format of
+     * which is scheme-specific and opaque to the framework.
+     * @return status the status of the call.
+     */
+    setPrivateData(vec<uint8_t> pvtData) generates (Status status);
+
+    /**
+     * Open a session to descramble one or more streams scrambled by the
+     * conditional access system.
+     *
+     * @return status the status of the call.
+     * @return sessionId the id of the newly opened session.
+     */
+    openSession() generates(Status status, HidlCasSessionId sessionId);
+
+    /**
+     * Close a session.
+     *
+     * @param sessionId the id of the session to be closed.
+     * @return status the status of the call.
+     */
+    closeSession(HidlCasSessionId sessionId) generates (Status status);
+
+    /**
+     * Provide the CA private data from a CA_descriptor in the program map
+     * table to a session.
+     *
+     * @param sessionId the id of the session which the private data applies to.
+     * @param pvtData a byte array containing the private data, the format of
+     * which is scheme-specific and opaque to the framework.
+     * @return status the status of the call.
+     */
+    setSessionPrivateData(HidlCasSessionId sessionId, vec<uint8_t> pvtData)
+        generates (Status status);
+
+    /**
+     * Process an ECM from the ECM stream for this session’s elementary stream.
+     *
+     * @param sessionId the id of the session which the ecm data applies to.
+     * @param ecm a byte array containing the ecm data.
+     * @return status the status of the call.
+     */
+    processEcm(HidlCasSessionId sessionId, vec<uint8_t> ecm)
+        generates (Status status);
+
+    /**
+     * Process an in-band EMM from the EMM stream.
+     *
+     * @param emm a byte array containing the emm data.
+     * @return status the status of the call.
+     */
+    processEmm(vec<uint8_t> emm) generates (Status status);
+
+    /**
+     * Send an scheme-specific event to the CasPlugin.
+     *
+     * @param event an integer denoting a scheme-specific event to be sent.
+     * @param arg a scheme-specific integer argument for the event.
+     * @param data a byte array containing scheme-specific data for the event.
+     * @return status the status of the call.
+     */
+    sendEvent(int32_t event, int32_t arg, vec<uint8_t> eventData)
+        generates (Status status);
+
+    /**
+     * Initiate a provisioning operation for a CA system.
+     *
+     * @param provisionString string containing information needed for the
+     * provisioning operation, the format of which is scheme and implementation
+     * specific.
+     * @return status the status of the call.
+     */
+    provision(string provisionString) generates (Status status);
+
+    /**
+     * Notify the CA system to refresh entitlement keys.
+     *
+     * @param refreshType the type of the refreshment.
+     * @param refreshData private data associated with the refreshment.
+     * @return status the status of the call.
+     */
+    refreshEntitlements(int32_t refreshType, vec<uint8_t> refreshData)
+        generates (Status status);
+
+    /**
+     * Release the descrambler instance.
+     *
+     * @return status the status of the call.
+     */
+    release() generates (Status status);
+};
diff --git a/cas/1.0/ICasListener.hal b/cas/1.0/ICasListener.hal
new file mode 100644
index 0000000..8ae6014
--- /dev/null
+++ b/cas/1.0/ICasListener.hal
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.cas@1.0;
+
+interface ICasListener {
+    /**
+      * Notify the listener of a scheme-specific event from the CA system.
+      *
+      * @param event an integer whose meaning is scheme-specific.
+      * @param arg an integer whose meaning is scheme-specific.
+      * @param data a byte array of data whose format and meaning are
+      * scheme-specific.
+      */
+    onEvent(int32_t event, int32_t arg, vec<uint8_t> data);
+};
diff --git a/cas/1.0/IDescramblerBase.hal b/cas/1.0/IDescramblerBase.hal
new file mode 100644
index 0000000..a126084
--- /dev/null
+++ b/cas/1.0/IDescramblerBase.hal
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.cas@1.0;
+
+import android.hardware.cas@1.0::types;
+
+/**
+ * IDescramblerBase is the API to control the descrambler and is accessible
+ * from both Java and native level.
+ */
+
+interface IDescramblerBase {
+    /**
+     * Associate a MediaCas session with this MediaDescrambler instance.
+     *
+     * @param sessionId the id of the session to associate with this descrambler instance.
+     * @return status the status of the call.
+     */
+    setMediaCasSession(HidlCasSessionId sessionId) generates (Status status);
+
+    /**
+     * Query if the scrambling scheme requires the use of a secure decoder
+     * to decode data of the given mime type.
+     *
+     * @param mime the mime type of the media data.
+     * @return result whether the descrambler requires a secure decoder.
+     */
+    requiresSecureDecoderComponent(string mime) generates (bool result);
+
+    /**
+     * Release the descrambler instance.
+     *
+     * @return status the status of the call.
+     */
+    release() generates (Status status);
+};
diff --git a/cas/1.0/IMediaCasService.hal b/cas/1.0/IMediaCasService.hal
new file mode 100644
index 0000000..cfeafad
--- /dev/null
+++ b/cas/1.0/IMediaCasService.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.cas@1.0;
+
+import android.hardware.cas@1.0::ICas;
+import android.hardware.cas@1.0::ICasListener;
+import android.hardware.cas@1.0::IDescramblerBase;
+
+/**
+ * IMediaCasService is the main entry point for interacting with a vendor's
+ * cas HAL to create cas and descrambler plugin instances. A cas plugin instance
+ * opens cas sessions which are used to obtain keys for a descrambler session,
+ * which can in turn be used to descramble protected video content.
+ */
+interface IMediaCasService {
+    /**
+     * List all available CA systems on the device.
+     *
+     * @return descriptors an array of descriptors for the available CA systems.
+     */
+    enumeratePlugins() generates (vec<HidlCasPluginDescriptor> descriptors);
+
+    /**
+     * Query if a certain CA system is supported on this device.
+     *
+     * @param CA_system_id the id of the CA system.
+     * @return result whether the specified CA system is supported on this device.
+     */
+    isSystemIdSupported(int32_t CA_system_id) generates (bool result);
+
+    /**
+     * Construct a new instance of a CasPlugin given a CA_system_id.
+     *
+     * @param CA_system_id the id of the CA system.
+     * @param listener the event listener to receive events coming from the CasPlugin.
+     * @return cas the newly created CasPlugin interface.
+     */
+    createPlugin(int32_t CA_system_id, ICasListener listener) generates (ICas cas);
+
+    /**
+     * Query if the descrambling scheme for a CA system is supported on this device.
+     *
+     * @param CA_system_id the id of the CA system.
+     * @return result whether the specified descrambling scheme is supported on this device.
+     */
+    isDescramblerSupported(int32_t CA_system_id) generates (bool result);
+
+    /**
+     * Construct a new instance of a DescramblerPlugin given a CA_system_id.
+     *
+     * @param CA_system_id the id of the CA system.
+     * @return descrambler the newly created plugin interface.
+     */
+    createDescrambler(int32_t CA_system_id) generates (IDescramblerBase descrambler);
+};
diff --git a/cas/1.0/default/Android.bp b/cas/1.0/default/Android.bp
new file mode 100644
index 0000000..953aa37
--- /dev/null
+++ b/cas/1.0/default/Android.bp
@@ -0,0 +1,35 @@
+cc_binary {
+    name: "android.hardware.cas@1.0-service",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+      "CasImpl.cpp",
+      "DescramblerImpl.cpp",
+      "MediaCasService.cpp",
+      "service.cpp",
+      "SharedLibrary.cpp",
+      "TypeConvert.cpp",
+    ],
+
+    product_variables: {
+        treble: {
+            cflags: ["-DUSE_VNDBINDER"],
+        },
+    },
+
+    compile_multilib: "32",
+    init_rc: ["android.hardware.cas@1.0-service.rc"],
+
+    shared_libs: [
+      "android.hardware.cas@1.0",
+      "android.hardware.cas.native@1.0",
+      "android.hidl.memory@1.0",
+      "libbinder",
+      "libhidlbase",
+      "libhidlmemory",
+      "libhidltransport",
+      "liblog",
+      "libutils",
+    ],
+}
diff --git a/cas/1.0/default/CasImpl.cpp b/cas/1.0/default/CasImpl.cpp
new file mode 100644
index 0000000..9d1f4a3
--- /dev/null
+++ b/cas/1.0/default/CasImpl.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.0-CasImpl"
+
+#include <android/hardware/cas/1.0/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "SharedLibrary.h"
+#include "TypeConvert.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+namespace implementation {
+
+struct CasImpl::PluginHolder : public RefBase {
+public:
+    explicit PluginHolder(CasPlugin *plugin) : mPlugin(plugin) {}
+    ~PluginHolder() { if (mPlugin != NULL) delete mPlugin; }
+    CasPlugin* get() { return mPlugin; }
+
+private:
+    CasPlugin *mPlugin;
+    DISALLOW_EVIL_CONSTRUCTORS(PluginHolder);
+};
+
+CasImpl::CasImpl(const sp<ICasListener> &listener)
+    : mPluginHolder(NULL), mListener(listener) {
+    ALOGV("CTOR");
+}
+
+CasImpl::~CasImpl() {
+    ALOGV("DTOR");
+    release();
+}
+
+//static
+void CasImpl::OnEvent(
+        void *appData,
+        int32_t event,
+        int32_t arg,
+        uint8_t *data,
+        size_t size) {
+    if (appData == NULL) {
+        ALOGE("Invalid appData!");
+        return;
+    }
+    CasImpl *casImpl = static_cast<CasImpl *>(appData);
+    casImpl->onEvent(event, arg, data, size);
+}
+
+void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin *plugin) {
+    mLibrary = library;
+    mPluginHolder = new PluginHolder(plugin);
+}
+
+void CasImpl::onEvent(
+        int32_t event, int32_t arg, uint8_t *data, size_t size) {
+    if (mListener == NULL) {
+        return;
+    }
+
+    HidlCasData eventData;
+    if (data != NULL) {
+        eventData.setToExternal(data, size);
+    }
+
+    mListener->onEvent(event, arg, eventData);
+}
+
+Return<Status> CasImpl::setPrivateData(const HidlCasData& pvtData) {
+    ALOGV("%s", __FUNCTION__);
+    sp<PluginHolder> holder = mPluginHolder;
+    if (holder == NULL) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->get()->setPrivateData(pvtData));
+}
+
+Return<void> CasImpl::openSession(openSession_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+    CasSessionId sessionId;
+
+    sp<PluginHolder> holder = mPluginHolder;
+    status_t err = INVALID_OPERATION;
+    if (holder != NULL) {
+        err = holder->get()->openSession(&sessionId);
+    }
+
+    _hidl_cb(toStatus(err), sessionId);
+
+    return Void();
+}
+
+Return<Status> CasImpl::setSessionPrivateData(
+        const HidlCasSessionId &sessionId, const HidlCasData& pvtData) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__,
+            sessionIdToString(sessionId).string());
+    sp<PluginHolder> holder = mPluginHolder;
+    if (holder == NULL) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(
+            holder->get()->setSessionPrivateData(
+                    sessionId, pvtData));
+}
+
+Return<Status> CasImpl::closeSession(const HidlCasSessionId &sessionId) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__,
+            sessionIdToString(sessionId).string());
+    sp<PluginHolder> holder = mPluginHolder;
+    if (holder == NULL) {
+        return toStatus(INVALID_OPERATION);
+    }
+    return toStatus(holder->get()->closeSession(sessionId));
+}
+
+Return<Status> CasImpl::processEcm(
+        const HidlCasSessionId &sessionId, const HidlCasData& ecm) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__,
+            sessionIdToString(sessionId).string());
+    sp<PluginHolder> holder = mPluginHolder;
+    if (holder == NULL) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->get()->processEcm(sessionId, ecm));
+}
+
+Return<Status> CasImpl::processEmm(const HidlCasData& emm) {
+    ALOGV("%s", __FUNCTION__);
+    sp<PluginHolder> holder = mPluginHolder;
+    if (holder == NULL) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->get()->processEmm(emm));
+}
+
+Return<Status> CasImpl::sendEvent(
+        int32_t event, int32_t arg,
+        const HidlCasData& eventData) {
+    ALOGV("%s", __FUNCTION__);
+    sp<PluginHolder> holder = mPluginHolder;
+    if (holder == NULL) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->get()->sendEvent(event, arg, eventData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::provision(const hidl_string& provisionString) {
+    ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
+    sp<PluginHolder> holder = mPluginHolder;
+    if (holder == NULL) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    return toStatus(holder->get()->provision(String8(provisionString.c_str())));
+}
+
+Return<Status> CasImpl::refreshEntitlements(
+        int32_t refreshType,
+        const HidlCasData& refreshData) {
+    ALOGV("%s", __FUNCTION__);
+    sp<PluginHolder> holder = mPluginHolder;
+    if (holder == NULL) {
+        return toStatus(INVALID_OPERATION);
+    }
+
+    status_t err = holder->get()->refreshEntitlements(refreshType, refreshData);
+    return toStatus(err);
+}
+
+Return<Status> CasImpl::release() {
+    ALOGV("%s: plugin=%p", __FUNCTION__,
+            mPluginHolder != NULL ? mPluginHolder->get() : NULL);
+    mPluginHolder.clear();
+    return Status::OK;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cas
+} // namespace hardware
+} // namespace android
diff --git a/cas/1.0/default/CasImpl.h b/cas/1.0/default/CasImpl.h
new file mode 100644
index 0000000..841d64e
--- /dev/null
+++ b/cas/1.0/default/CasImpl.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_0_CAS_IMPL_H_
+#define ANDROID_HARDWARE_CAS_V1_0_CAS_IMPL_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <android/hardware/cas/1.0/ICas.h>
+
+namespace android {
+struct CasPlugin;
+
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+struct ICasListener;
+namespace implementation {
+
+class SharedLibrary;
+
+class CasImpl : public ICas {
+public:
+    CasImpl(const sp<ICasListener> &listener);
+    virtual ~CasImpl();
+
+    static void OnEvent(
+            void *appData,
+            int32_t event,
+            int32_t arg,
+            uint8_t *data,
+            size_t size);
+
+    void init(const sp<SharedLibrary>& library, CasPlugin *plugin);
+    void onEvent(
+            int32_t event,
+            int32_t arg,
+            uint8_t *data,
+            size_t size);
+
+    // ICas inherits
+
+    virtual Return<Status> setPrivateData(
+            const HidlCasData& pvtData) override;
+
+    virtual Return<void> openSession(
+            openSession_cb _hidl_cb) override;
+
+    virtual Return<Status> closeSession(
+            const HidlCasSessionId& sessionId) override;
+
+    virtual Return<Status> setSessionPrivateData(
+            const HidlCasSessionId& sessionId,
+            const HidlCasData& pvtData) override;
+
+    virtual Return<Status> processEcm(
+            const HidlCasSessionId& sessionId,
+            const HidlCasData& ecm) override;
+
+    virtual Return<Status> processEmm(
+            const HidlCasData& emm) override;
+
+    virtual Return<Status> sendEvent(
+            int32_t event, int32_t arg,
+            const HidlCasData& eventData) override;
+
+    virtual Return<Status> provision(
+            const hidl_string& provisionString) override;
+
+    virtual Return<Status> refreshEntitlements(
+            int32_t refreshType,
+            const HidlCasData& refreshData) override;
+
+    virtual Return<Status> release() override;
+
+private:
+    struct PluginHolder;
+    sp<SharedLibrary> mLibrary;
+    sp<PluginHolder> mPluginHolder;
+    sp<ICasListener> mListener;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cas
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_0_CAS_IMPL_H_
diff --git a/cas/1.0/default/DescramblerImpl.cpp b/cas/1.0/default/DescramblerImpl.cpp
new file mode 100644
index 0000000..3d90809
--- /dev/null
+++ b/cas/1.0/default/DescramblerImpl.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.0-DescramblerImpl"
+
+#include <hidlmemory/mapping.h>
+#include <media/hardware/CryptoAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <utils/Log.h>
+
+#include "DescramblerImpl.h"
+#include "SharedLibrary.h"
+#include "TypeConvert.h"
+
+namespace android {
+using hidl::memory::V1_0::IMemory;
+
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+namespace implementation {
+
+#define CHECK_SUBSAMPLE_DEF(type) \
+static_assert(sizeof(SubSample) == sizeof(type::SubSample), \
+        "SubSample: size doesn't match"); \
+static_assert(offsetof(SubSample, numBytesOfClearData) \
+        == offsetof(type::SubSample, mNumBytesOfClearData), \
+        "SubSample: numBytesOfClearData offset doesn't match"); \
+static_assert(offsetof(SubSample, numBytesOfEncryptedData) \
+        == offsetof(type::SubSample, mNumBytesOfEncryptedData), \
+        "SubSample: numBytesOfEncryptedData offset doesn't match")
+
+CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
+CHECK_SUBSAMPLE_DEF(CryptoPlugin);
+
+DescramblerImpl::DescramblerImpl(
+        const sp<SharedLibrary>& library, DescramblerPlugin *plugin) :
+        mLibrary(library), mPlugin(plugin) {
+    ALOGV("CTOR: mPlugin=%p", mPlugin);
+}
+
+DescramblerImpl::~DescramblerImpl() {
+    ALOGV("DTOR: mPlugin=%p", mPlugin);
+    release();
+}
+
+Return<Status> DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) {
+    ALOGV("%s: sessionId=%s", __FUNCTION__,
+            sessionIdToString(sessionId).string());
+
+    return toStatus(mPlugin->setMediaCasSession(sessionId));
+}
+
+Return<bool> DescramblerImpl::requiresSecureDecoderComponent(
+        const hidl_string& mime) {
+    return mPlugin->requiresSecureDecoderComponent(String8(mime.c_str()));
+}
+
+Return<void> DescramblerImpl::descramble(
+        ScramblingControl scramblingControl,
+        const hidl_vec<SubSample>& subSamples,
+        const SharedBuffer& srcBuffer,
+        uint64_t srcOffset,
+        const DestinationBuffer& dstBuffer,
+        uint64_t dstOffset,
+        descramble_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    sp<IMemory> srcMem = mapMemory(srcBuffer.heapBase);
+    void *srcPtr = (uint8_t *)(void *)srcMem->getPointer() + srcBuffer.offset;
+    void *dstPtr = NULL;
+    if (dstBuffer.type == BufferType::SHARED_MEMORY) {
+        // When using shared memory, src buffer is also used as dst,
+        // we don't map it again here.
+        dstPtr = srcPtr;
+    } else {
+        native_handle_t *handle = const_cast<native_handle_t *>(
+                dstBuffer.secureMemory.getNativeHandle());
+        dstPtr = static_cast<void *>(handle);
+    }
+    // Casting hidl SubSample to DescramblerPlugin::SubSample, but need
+    // to ensure structs are actually idential
+
+    int32_t result = mPlugin->descramble(
+            dstBuffer.type != BufferType::SHARED_MEMORY,
+            (DescramblerPlugin::ScramblingControl)scramblingControl,
+            subSamples.size(),
+            (DescramblerPlugin::SubSample*)subSamples.data(),
+            srcPtr,
+            srcOffset,
+            dstPtr,
+            dstOffset,
+            NULL);
+
+    _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL);
+    return Void();
+}
+
+Return<Status> DescramblerImpl::release() {
+    ALOGV("%s: mPlugin=%p", __FUNCTION__, mPlugin);
+
+    if (mPlugin != NULL) {
+        delete mPlugin;
+        mPlugin = NULL;
+    }
+    return Status::OK;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cas
+} // namespace hardware
+} // namespace android
diff --git a/cas/1.0/default/DescramblerImpl.h b/cas/1.0/default/DescramblerImpl.h
new file mode 100644
index 0000000..d3b146e
--- /dev/null
+++ b/cas/1.0/default/DescramblerImpl.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_0_DESCRAMBLER_IMPL_H_
+#define ANDROID_HARDWARE_CAS_V1_0_DESCRAMBLER_IMPL_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <android/hardware/cas/native/1.0/IDescrambler.h>
+
+namespace android {
+struct DescramblerPlugin;
+using namespace hardware::cas::native::V1_0;
+
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+namespace implementation {
+
+class SharedLibrary;
+
+class DescramblerImpl : public IDescrambler {
+public:
+    DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin *plugin);
+    virtual ~DescramblerImpl();
+
+    virtual Return<Status> setMediaCasSession(
+            const HidlCasSessionId& sessionId) override;
+
+    virtual Return<bool> requiresSecureDecoderComponent(
+            const hidl_string& mime) override;
+
+    virtual Return<void> descramble(
+            ScramblingControl scramblingControl,
+            const hidl_vec<SubSample>& subSamples,
+            const SharedBuffer& srcBuffer,
+            uint64_t srcOffset,
+            const DestinationBuffer& dstBuffer,
+            uint64_t dstOffset,
+            descramble_cb _hidl_cb) override;
+
+    virtual Return<Status> release() override;
+
+private:
+    sp<SharedLibrary> mLibrary;
+    DescramblerPlugin *mPlugin;
+
+    DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cas
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_0_DESCRAMBLER_IMPL_H_
diff --git a/cas/1.0/default/FactoryLoader.h b/cas/1.0/default/FactoryLoader.h
new file mode 100644
index 0000000..18c2186
--- /dev/null
+++ b/cas/1.0/default/FactoryLoader.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_
+#define ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include "SharedLibrary.h"
+#include <utils/KeyedVector.h>
+#include <utils/Mutex.h>
+#include <media/cas/CasAPI.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+namespace implementation {
+
+template <class T>
+class FactoryLoader {
+public:
+    FactoryLoader(const char *name) :
+        mFactory(NULL), mCreateFactoryFuncName(name) {}
+
+    virtual ~FactoryLoader() { closeFactory(); }
+
+    bool findFactoryForScheme(
+            int32_t CA_system_id,
+            sp<SharedLibrary> *library = NULL,
+            T** factory = NULL);
+
+    bool enumeratePlugins(vector<HidlCasPluginDescriptor>* results);
+
+private:
+    typedef T*(*CreateFactoryFunc)();
+
+    Mutex mMapLock;
+    T* mFactory;
+    const char *mCreateFactoryFuncName;
+    sp<SharedLibrary> mLibrary;
+    KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
+    KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
+
+    bool loadFactoryForSchemeFromPath(
+            const String8 &path,
+            int32_t CA_system_id,
+            sp<SharedLibrary> *library,
+            T** factory);
+
+    bool queryPluginsFromPath(
+            const String8 &path,
+            vector<HidlCasPluginDescriptor>* results);
+
+    bool openFactory(const String8 &path);
+    void closeFactory();
+};
+
+template <class T>
+bool FactoryLoader<T>::findFactoryForScheme(
+        int32_t CA_system_id, sp<SharedLibrary> *library, T** factory) {
+    if (library != NULL) {
+        library->clear();
+    }
+    if (factory != NULL) {
+        *factory = NULL;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    // first check cache
+    ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
+    if (index >= 0) {
+        return loadFactoryForSchemeFromPath(
+                mCASystemIdToLibraryPathMap[index],
+                CA_system_id, library, factory);
+    }
+
+    // no luck, have to search
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            if (loadFactoryForSchemeFromPath(
+                    pluginPath, CA_system_id, library, factory)) {
+                mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
+                closedir(pDir);
+
+                return true;
+            }
+        }
+    }
+
+    closedir(pDir);
+
+    ALOGE("Failed to find plugin");
+    return false;
+}
+
+template <class T>
+bool FactoryLoader<T>::enumeratePlugins(
+        vector<HidlCasPluginDescriptor>* results) {
+    ALOGI("enumeratePlugins");
+
+    results->clear();
+
+    String8 dirPath("/vendor/lib/mediacas");
+    DIR* pDir = opendir(dirPath.string());
+
+    if (pDir == NULL) {
+        ALOGE("Failed to open plugin directory %s", dirPath.string());
+        return false;
+    }
+
+    Mutex::Autolock autoLock(mMapLock);
+
+    struct dirent* pEntry;
+    while ((pEntry = readdir(pDir))) {
+        String8 pluginPath = dirPath + "/" + pEntry->d_name;
+        if (pluginPath.getPathExtension() == ".so") {
+            queryPluginsFromPath(pluginPath, results);
+        }
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::loadFactoryForSchemeFromPath(
+        const String8 &path, int32_t CA_system_id,
+        sp<SharedLibrary> *library, T** factory) {
+    closeFactory();
+
+    if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
+        closeFactory();
+        return false;
+    }
+
+    if (library != NULL) {
+        *library = mLibrary;
+    }
+    if (factory != NULL) {
+        *factory = mFactory;
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::queryPluginsFromPath(
+        const String8 &path, vector<HidlCasPluginDescriptor>* results) {
+    closeFactory();
+
+    vector<CasPluginDescriptor> descriptors;
+    if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
+        closeFactory();
+        return false;
+    }
+
+    for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
+        results->push_back( HidlCasPluginDescriptor {
+                .caSystemId = it->CA_system_id,
+                .name = it->name.c_str()});
+    }
+    return true;
+}
+
+template <class T>
+bool FactoryLoader<T>::openFactory(const String8 &path) {
+    // get strong pointer to open shared library
+    ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+    if (index >= 0) {
+        mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+    } else {
+        index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+    }
+
+    if (!mLibrary.get()) {
+        mLibrary = new SharedLibrary(path);
+        if (!*mLibrary) {
+            return false;
+        }
+
+        mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
+    }
+
+    CreateFactoryFunc createFactory =
+        (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
+    if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
+        return false;
+    }
+    return true;
+}
+
+template <class T>
+void FactoryLoader<T>::closeFactory() {
+    delete mFactory;
+    mFactory = NULL;
+    mLibrary.clear();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cas
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_0_FACTORY_LOADER_H_
diff --git a/cas/1.0/default/MediaCasService.cpp b/cas/1.0/default/MediaCasService.cpp
new file mode 100644
index 0000000..ca43224
--- /dev/null
+++ b/cas/1.0/default/MediaCasService.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.0-MediaCasService"
+
+#include <android/hardware/cas/1.0/ICasListener.h>
+#include <media/cas/CasAPI.h>
+#include <media/cas/DescramblerAPI.h>
+#include <utils/Log.h>
+
+#include "CasImpl.h"
+#include "DescramblerImpl.h"
+#include "MediaCasService.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+namespace implementation {
+
+MediaCasService::MediaCasService() :
+    mCasLoader("createCasFactory"),
+    mDescramblerLoader("createDescramblerFactory") {
+}
+
+MediaCasService::~MediaCasService() {
+}
+
+Return<void> MediaCasService::enumeratePlugins(enumeratePlugins_cb _hidl_cb) {
+
+    ALOGV("%s", __FUNCTION__);
+
+    vector<HidlCasPluginDescriptor> results;
+    mCasLoader.enumeratePlugins(&results);
+
+    _hidl_cb(results);
+    return Void();
+}
+
+Return<bool> MediaCasService::isSystemIdSupported(int32_t CA_system_id) {
+    ALOGV("isSystemIdSupported: CA_system_id=%d", CA_system_id);
+
+    return mCasLoader.findFactoryForScheme(CA_system_id);
+}
+
+Return<sp<ICas>> MediaCasService::createPlugin(
+        int32_t CA_system_id, const sp<ICasListener>& listener) {
+
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    sp<ICas> result;
+
+    CasFactory *factory;
+    sp<SharedLibrary> library;
+    if (mCasLoader.findFactoryForScheme(CA_system_id, &library, &factory)) {
+        CasPlugin *plugin = NULL;
+        sp<CasImpl> casImpl = new CasImpl(listener);
+        if (factory->createPlugin(CA_system_id, (uint64_t)casImpl.get(),
+                &CasImpl::OnEvent, &plugin) == OK && plugin != NULL) {
+            casImpl->init(library, plugin);
+            result = casImpl;
+        }
+    }
+
+    return result;
+}
+
+Return<bool> MediaCasService::isDescramblerSupported(int32_t CA_system_id) {
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    return mDescramblerLoader.findFactoryForScheme(CA_system_id);
+}
+
+Return<sp<IDescramblerBase>> MediaCasService::createDescrambler(int32_t CA_system_id) {
+
+    ALOGV("%s: CA_system_id=%d", __FUNCTION__, CA_system_id);
+
+    sp<IDescrambler> result;
+
+    DescramblerFactory *factory;
+    sp<SharedLibrary> library;
+    if (mDescramblerLoader.findFactoryForScheme(
+            CA_system_id, &library, &factory)) {
+        DescramblerPlugin *plugin = NULL;
+        if (factory->createPlugin(CA_system_id, &plugin) == OK
+                && plugin != NULL) {
+            result = new DescramblerImpl(library, plugin);
+        }
+    }
+
+    return result;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cas
+} // namespace hardware
+} // namespace android
diff --git a/cas/1.0/default/MediaCasService.h b/cas/1.0/default/MediaCasService.h
new file mode 100644
index 0000000..77ddac6
--- /dev/null
+++ b/cas/1.0/default/MediaCasService.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_0_MEDIA_CAS_SERVICE_H_
+#define ANDROID_HARDWARE_CAS_V1_0_MEDIA_CAS_SERVICE_H_
+
+#include <android/hardware/cas/1.0/IMediaCasService.h>
+
+#include "FactoryLoader.h"
+
+namespace android {
+struct CasFactory;
+struct DescramblerFactory;
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+namespace implementation {
+
+class MediaCasService : public IMediaCasService {
+public:
+    MediaCasService();
+
+    virtual Return<void> enumeratePlugins(
+            enumeratePlugins_cb _hidl_cb) override;
+
+    virtual Return<bool> isSystemIdSupported(
+            int32_t CA_system_id) override;
+
+    virtual Return<sp<ICas>> createPlugin(
+            int32_t CA_system_id, const sp<ICasListener>& listener) override;
+
+    virtual Return<bool> isDescramblerSupported(
+            int32_t CA_system_id) override;
+
+    virtual Return<sp<IDescramblerBase>> createDescrambler(
+            int32_t CA_system_id) override;
+
+private:
+    FactoryLoader<CasFactory> mCasLoader;
+    FactoryLoader<DescramblerFactory> mDescramblerLoader;
+
+    virtual ~MediaCasService();
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace cas
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_0_MEDIA_CAS_SERVICE_H_
diff --git a/cas/1.0/default/SharedLibrary.cpp b/cas/1.0/default/SharedLibrary.cpp
new file mode 100644
index 0000000..9c7f385
--- /dev/null
+++ b/cas/1.0/default/SharedLibrary.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.0-SharedLibrary"
+
+#include <dlfcn.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include "SharedLibrary.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+namespace implementation {
+
+SharedLibrary::SharedLibrary(const String8 &path) {
+    mLibHandle = dlopen(path.string(), RTLD_NOW);
+}
+
+SharedLibrary::~SharedLibrary() {
+    if (mLibHandle != NULL) {
+        dlclose(mLibHandle);
+        mLibHandle = NULL;
+    }
+}
+
+bool SharedLibrary::operator!() const {
+    return mLibHandle == NULL;
+}
+
+void *SharedLibrary::lookup(const char *symbol) const {
+    if (!mLibHandle) {
+        return NULL;
+    }
+    // Clear last error before we load the symbol again,
+    // in case the caller didn't retrieve it.
+    (void)dlerror();
+    return dlsym(mLibHandle, symbol);
+}
+
+const char *SharedLibrary::lastError() const {
+    const char *error = dlerror();
+    return error ? error : "No errors or unknown error";
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/cas/1.0/default/SharedLibrary.h b/cas/1.0/default/SharedLibrary.h
new file mode 100644
index 0000000..18130a5
--- /dev/null
+++ b/cas/1.0/default/SharedLibrary.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAS_V1_0_SHARED_LIBRARY_H_
+#define ANDROID_HARDWARE_CAS_V1_0_SHARED_LIBRARY_H_
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+namespace implementation {
+
+class SharedLibrary : public RefBase {
+public:
+    explicit SharedLibrary(const String8 &path);
+    ~SharedLibrary();
+
+    bool operator!() const;
+    void *lookup(const char *symbol) const;
+    const char *lastError() const;
+
+private:
+    void *mLibHandle;
+    DISALLOW_EVIL_CONSTRUCTORS(SharedLibrary);
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
+
+#endif // ANDROID_HARDWARE_CAS_V1_0_SHARED_LIBRARY_H_
diff --git a/cas/1.0/default/TypeConvert.cpp b/cas/1.0/default/TypeConvert.cpp
new file mode 100644
index 0000000..de1f92b
--- /dev/null
+++ b/cas/1.0/default/TypeConvert.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.0-TypeConvert"
+
+#include <utils/Log.h>
+#include "TypeConvert.h"
+
+namespace android {
+namespace hardware {
+namespace cas {
+namespace V1_0 {
+namespace implementation {
+
+Status toStatus(status_t legacyStatus) {
+    Status status;
+    switch(legacyStatus) {
+    case android::OK:
+        status = Status::OK;
+        break;
+    case android::ERROR_CAS_NO_LICENSE:
+        status = Status::ERROR_CAS_NO_LICENSE;
+        break;
+    case android::ERROR_CAS_LICENSE_EXPIRED:
+        status = Status::ERROR_CAS_LICENSE_EXPIRED;
+        break;
+    case android::ERROR_CAS_SESSION_NOT_OPENED:
+        status = Status::ERROR_CAS_SESSION_NOT_OPENED;
+        break;
+    case android::ERROR_CAS_CANNOT_HANDLE:
+        status = Status::ERROR_CAS_CANNOT_HANDLE;
+        break;
+    case android::ERROR_CAS_TAMPER_DETECTED:
+        status = Status::ERROR_CAS_INVALID_STATE;
+        break;
+    case android::BAD_VALUE:
+        status = Status::BAD_VALUE;
+        break;
+    case android::ERROR_CAS_NOT_PROVISIONED:
+        status = Status::ERROR_CAS_NOT_PROVISIONED;
+        break;
+    case android::ERROR_CAS_RESOURCE_BUSY:
+        status = Status::ERROR_CAS_RESOURCE_BUSY;
+        break;
+    case android::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
+        status = Status::ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION;
+        break;
+    case android::ERROR_CAS_DEVICE_REVOKED:
+        status = Status::ERROR_CAS_DEVICE_REVOKED;
+        break;
+    case android::ERROR_CAS_DECRYPT:
+        status = Status::ERROR_CAS_DECRYPT;
+        break;
+    default:
+        ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN",
+            legacyStatus);
+        status = Status::ERROR_CAS_UNKNOWN;
+        break;
+    }
+    return status;
+}
+
+String8 sessionIdToString(const CasSessionId &sessionId) {
+    String8 result;
+    for (size_t i = 0; i < sessionId.size(); i++) {
+        result.appendFormat("%02x ", sessionId[i]);
+    }
+    if (result.isEmpty()) {
+        result.append("(null)");
+    }
+    return result;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace cas
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.0/default/wifi_feature_flags.h b/cas/1.0/default/TypeConvert.h
similarity index 60%
copy from wifi/1.0/default/wifi_feature_flags.h
copy to cas/1.0/default/TypeConvert.h
index 3502fbd..7c3dded 100644
--- a/wifi/1.0/default/wifi_feature_flags.h
+++ b/cas/1.0/default/TypeConvert.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,28 +14,28 @@
  * limitations under the License.
  */
 
-#ifndef WIFI_FEATURE_FLAGS_H_
-#define WIFI_FEATURE_FLAGS_H_
+#ifndef ANDROID_HARDWARE_CAS_V1_0_TYPE_CONVERT_H
+#define ANDROID_HARDWARE_CAS_V1_0_TYPE_CONVERT_H
+
+#include <android/hardware/cas/1.0/types.h>
+#include <media/cas/CasAPI.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/String8.h>
 
 namespace android {
 namespace hardware {
-namespace wifi {
+namespace cas {
 namespace V1_0 {
 namespace implementation {
 
-class WifiFeatureFlags {
- public:
-#ifdef WIFI_HIDL_FEATURE_AWARE
-  static const bool wifiHidlFeatureAware = true;
-#else
-  static const bool wifiHidlFeatureAware = false;
-#endif // WIFI_HIDL_FEATURE_AWARE
-};
+Status toStatus(status_t legacyStatus);
+
+String8 sessionIdToString(const CasSessionId &sessionId);
 
 }  // namespace implementation
 }  // namespace V1_0
-}  // namespace wifi
+}  // namespace cas
 }  // namespace hardware
 }  // namespace android
 
-#endif  // WIFI_FEATURE_FLAGS_H_
+#endif // ANDROID_HARDWARE_CAS_V1_0_TYPE_CONVERT_H
diff --git a/cas/1.0/default/android.hardware.cas@1.0-service.rc b/cas/1.0/default/android.hardware.cas@1.0-service.rc
new file mode 100644
index 0000000..93de794
--- /dev/null
+++ b/cas/1.0/default/android.hardware.cas@1.0-service.rc
@@ -0,0 +1,6 @@
+service cas-hal-1-0 /vendor/bin/hw/android.hardware.cas@1.0-service
+    class hal
+    user media
+    group mediadrm drmrpc
+    ioprio rt 4
+    writepid /dev/cpuset/foreground/tasks
diff --git a/cas/1.0/default/service.cpp b/cas/1.0/default/service.cpp
new file mode 100644
index 0000000..3f1df5a
--- /dev/null
+++ b/cas/1.0/default/service.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "android.hardware.cas@1.0-service"
+
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hidl/LegacySupport.h>
+
+#include "MediaCasService.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::cas::V1_0::implementation::MediaCasService;
+using android::hardware::cas::V1_0::IMediaCasService;
+
+int main() {
+    ALOGD("android.hardware.cas@1.0-service starting...");
+
+#ifdef USE_VNDBINDER
+    // The CAS HAL may communicate to other vendor components via
+    // /dev/vndbinder
+    android::ProcessState::initWithDriver("/dev/vndbinder");
+#endif // USE_VNDBINDER
+
+    configureRpcThreadpool(8, true /* callerWillJoin */);
+
+    // Setup hwbinder service
+    android::sp<IMediaCasService> service = new MediaCasService();
+    android::status_t status = service->registerAsService();
+    LOG_ALWAYS_FATAL_IF(
+            status != android::OK,
+            "Error while registering cas service: %d", status);
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/cas/1.0/types.hal b/cas/1.0/types.hal
new file mode 100644
index 0000000..7337f00
--- /dev/null
+++ b/cas/1.0/types.hal
@@ -0,0 +1,124 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas@1.0;
+
+enum Status : uint32_t {
+    /**
+     * The CAS plugin must return OK when an operation completes without any
+     * errors.
+     */
+    OK,
+
+    /**
+     * The CAS plugin must return ERROR_CAS_NO_LICENSE, when descrambling is
+     * attempted and no license keys have been provided.
+     */
+    ERROR_CAS_NO_LICENSE,
+
+    /**
+     * ERROR_CAS_LICENSE_EXPIRED must be returned when an attempt is made
+     * to use a license and the keys in that license have expired.
+     */
+    ERROR_CAS_LICENSE_EXPIRED,
+
+    /**
+     * The CAS plugin must return ERROR_CAS_SESSION_NOT_OPENED when an
+     * attempt is made to use a session that has not been opened.
+     */
+    ERROR_CAS_SESSION_NOT_OPENED,
+
+    /**
+     * The CAS plugin must return ERROR_CAS_CANNOT_HANDLE when an unsupported
+     * data format or operation is attempted.
+     */
+    ERROR_CAS_CANNOT_HANDLE,
+
+    /**
+     * ERROR_CAS_INVALID_STATE must be returned when the device is in a state
+     * where it is not able to perform descrambling.
+     */
+    ERROR_CAS_INVALID_STATE,
+
+    /**
+     * The CAS plugin must return BAD_VALUE whenever an illegal parameter is
+     * passed to one of the interface functions.
+     */
+    BAD_VALUE,
+
+    /**
+     * The CAS plugin must return ERROR_CAS_NOT_PROVISIONED when the device
+     * has not yet been provisioned.
+     */
+    ERROR_CAS_NOT_PROVISIONED,
+
+    /**
+     * ERROR_CAS_RESOURCE_BUSY must be returned when resources, such as CAS
+     * sessions or secure buffers are not available to perform a requested
+     * operation because they are already in use.
+     */
+    ERROR_CAS_RESOURCE_BUSY,
+
+    /**
+     * The CAS Plugin must return ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION
+     * when the output protection level enabled on the device is not
+     * sufficient to meet the requirements in the license policy. HDCP is an
+     * example of a form of output protection.
+     */
+    ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION,
+
+    /**
+     * The CAS Plugin must return ERROR_CAS_TAMPER_DETECTED if an attempt to
+     * tamper with the CAS system is detected.
+     */
+    ERROR_CAS_TAMPER_DETECTED,
+
+    /**
+     * The CAS Plugin must return ERROR_CAS_DEVICE_REVOKED if the response
+     * indicates that the device has been revoked. Device revocation means
+     * that the device is no longer permitted to play content.
+     */
+    ERROR_CAS_DEVICE_REVOKED,
+
+    /**
+     * The CAS plugin must return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED when
+     * descrambling is failing because the session is not initialized properly.
+     */
+    ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED,
+
+    /**
+     * The CAS Plugin must return ERROR_CAS_DECRYPT if the DescramblerPlugin's
+     * descramble operation fails.
+     */
+    ERROR_CAS_DECRYPT,
+
+    /**
+     * ERROR_CAS_UNKNOWN must be returned when a fatal failure occurs and no
+     * other defined error is appropriate.
+     */
+    ERROR_CAS_UNKNOWN,
+};
+
+typedef vec<uint8_t> HidlCasSessionId;
+typedef vec<uint8_t> HidlCasData;
+
+/**
+ * Describes a CAS plugin with its system id and name.
+ */
+struct HidlCasPluginDescriptor {
+    int32_t caSystemId;
+    string name;
+};
diff --git a/cas/Android.bp b/cas/Android.bp
new file mode 100644
index 0000000..57532a0
--- /dev/null
+++ b/cas/Android.bp
@@ -0,0 +1,6 @@
+// This is an autogenerated file, do not edit.
+subdirs = [
+    "1.0",
+    "1.0/default",
+    "native/1.0",
+]
diff --git a/cas/native/1.0/Android.bp b/cas/native/1.0/Android.bp
new file mode 100644
index 0000000..414fca7
--- /dev/null
+++ b/cas/native/1.0/Android.bp
@@ -0,0 +1,65 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+    name: "android.hardware.cas.native@1.0_hal",
+    srcs: [
+        "types.hal",
+        "IDescrambler.hal",
+    ],
+}
+
+genrule {
+    name: "android.hardware.cas.native@1.0_genc++",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas.native@1.0",
+    srcs: [
+        ":android.hardware.cas.native@1.0_hal",
+    ],
+    out: [
+        "android/hardware/cas/native/1.0/types.cpp",
+        "android/hardware/cas/native/1.0/DescramblerAll.cpp",
+    ],
+}
+
+genrule {
+    name: "android.hardware.cas.native@1.0_genc++_headers",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.cas.native@1.0",
+    srcs: [
+        ":android.hardware.cas.native@1.0_hal",
+    ],
+    out: [
+        "android/hardware/cas/native/1.0/types.h",
+        "android/hardware/cas/native/1.0/hwtypes.h",
+        "android/hardware/cas/native/1.0/IDescrambler.h",
+        "android/hardware/cas/native/1.0/IHwDescrambler.h",
+        "android/hardware/cas/native/1.0/BnHwDescrambler.h",
+        "android/hardware/cas/native/1.0/BpHwDescrambler.h",
+        "android/hardware/cas/native/1.0/BsDescrambler.h",
+    ],
+}
+
+cc_library_shared {
+    name: "android.hardware.cas.native@1.0",
+    defaults: ["hidl-module-defaults"],
+    generated_sources: ["android.hardware.cas.native@1.0_genc++"],
+    generated_headers: ["android.hardware.cas.native@1.0_genc++_headers"],
+    export_generated_headers: ["android.hardware.cas.native@1.0_genc++_headers"],
+    vendor_available: true,
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libutils",
+        "libcutils",
+        "android.hardware.cas@1.0",
+    ],
+    export_shared_lib_headers: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+        "android.hardware.cas@1.0",
+    ],
+}
diff --git a/cas/native/1.0/IDescrambler.hal b/cas/native/1.0/IDescrambler.hal
new file mode 100644
index 0000000..459e5e3
--- /dev/null
+++ b/cas/native/1.0/IDescrambler.hal
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.cas.native@1.0;
+
+import android.hardware.cas@1.0::IDescramblerBase;
+
+/**
+ * IDescrambler is the native plugin API for descrambling operations.
+ */
+
+interface IDescrambler extends IDescramblerBase {
+    /**
+     * Descramble the data in a source SharedBuffer, described by an array of
+     * SubSample structures.
+     *
+     * @param scramblingControl an enumeration indicating the key that the subsamples
+     * were scrambled with.
+     * @param subSamples an array of SubSample structures describing the number of
+     * clear and scrambled bytes within each subsample.
+     * @param srcBuffer the SharedBuffer containing the source scrambled data.
+     * @param srcOffset the position where the source scrambled data starts at.
+     * @param dstBuffer the DestinationBuffer to hold the descrambled data.
+     * @param dstOffset the position where the descrambled data should start at.
+     *
+     * @return status the status of the call.
+     * @return bytesWritten number of bytes that have been successfully descrambled.
+     * @return detailedError a detailed message describing the error (if any).
+     */
+    descramble(ScramblingControl scramblingControl, vec<SubSample> subSamples,
+        SharedBuffer srcBuffer, uint64_t srcOffset, DestinationBuffer dstBuffer, uint64_t dstOffset)
+        generates(Status status, uint32_t bytesWritten, string detailedError);
+};
diff --git a/cas/native/1.0/types.hal b/cas/native/1.0/types.hal
new file mode 100644
index 0000000..a576d03
--- /dev/null
+++ b/cas/native/1.0/types.hal
@@ -0,0 +1,90 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cas.native@1.0;
+
+import android.hardware.cas@1.0::types;
+
+/**
+ * Enumerates the keys used to scramble the content.
+ */
+enum ScramblingControl : uint32_t {
+    UNSCRAMBLED = 0,
+    RESERVED    = 1,
+    EVENKEY     = 2,
+    ODDKEY      = 3,
+};
+
+/**
+ * A subsample consists of some number of bytes of clear (unscrambled)
+ * data followed by a number of bytes of scrambled data.
+ */
+struct SubSample {
+    uint32_t numBytesOfClearData;
+    uint32_t numBytesOfEncryptedData;
+};
+
+/**
+ * SharedBuffer describes a shared buffer which is defined by a heapBase, an
+ * offset and a size. The offset is relative to the shared memory base for the
+ * memory region identified by heapBase.
+ */
+struct SharedBuffer {
+    /**
+     * The shared memory base handle
+     */
+    memory heapBase;
+
+    /**
+     * The offset from the shared memory base
+     */
+    uint64_t offset;
+
+    /**
+     * The size of the shared buffer in bytes
+     */
+    uint64_t size;
+};
+
+/**
+ * A descrambling destination buffer can be either normal user-space shared
+ * memory for the non-secure descrambling case, or it can be a secure buffer
+ * which is referenced by a native-handle. The native handle is allocated
+ * by the vendor's buffer allocator.
+ */
+enum BufferType : uint32_t {
+    SHARED_MEMORY = 0,
+    NATIVE_HANDLE = 1,
+};
+
+struct DestinationBuffer {
+    /**
+     * The type of the buffer
+     */
+    BufferType type;
+
+    /**
+     * If type == SHARED_MEMORY, the descrambled data must be written
+     * to user-space non-secure shared memory.
+     */
+    SharedBuffer nonsecureMemory;
+
+    /**
+     * If type == NATIVE_HANDLE, the descrambled data must be written
+     * to secure memory referenced by the vendor's buffer allocator.
+     */
+    handle secureMemory;
+};
diff --git a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
index 95cd30b..e501580 100644
--- a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
+++ b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
@@ -41,6 +41,7 @@
     virtual void SetUp() override {
         sfConfigs = ::testing::VtsHalHidlTargetTestBase::getService<
             ISurfaceFlingerConfigs>();
+        ASSERT_NE(sfConfigs, nullptr);
     }
 
     virtual void TearDown() override {}
diff --git a/configstore/1.1/vts/functional/Android.bp b/configstore/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..5cfa483
--- /dev/null
+++ b/configstore/1.1/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalConfigstoreV1_1TargetTest",
+    defaults: ["hidl_defaults"],
+    srcs: ["VtsHalConfigstoreV1_1TargetTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.configstore@1.1",
+    ],
+    static_libs: ["VtsHalHidlTargetTestBase"],
+    cflags: [
+        "-O0",
+        "-g",
+    ]
+}
+
diff --git a/configstore/1.1/vts/functional/VtsHalConfigstoreV1_1TargetTest.cpp b/configstore/1.1/vts/functional/VtsHalConfigstoreV1_1TargetTest.cpp
new file mode 100644
index 0000000..bd3da4c
--- /dev/null
+++ b/configstore/1.1/vts/functional/VtsHalConfigstoreV1_1TargetTest.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ConfigstoreHidlHalTest"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/configstore/1.0/types.h>
+#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
+#include <unistd.h>
+
+using ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs;
+using ::android::sp;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+class ConfigstoreHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    sp<ISurfaceFlingerConfigs> sfConfigs;
+
+    virtual void SetUp() override {
+        sfConfigs = ::testing::VtsHalHidlTargetTestBase::getService<ISurfaceFlingerConfigs>();
+        ASSERT_NE(sfConfigs, nullptr);
+    }
+
+    virtual void TearDown() override {}
+};
+
+/**
+ * Placeholder testcase.
+ */
+TEST_F(ConfigstoreHidlTest, Test) {
+    ASSERT_TRUE(true);
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/configstore/Android.bp b/configstore/Android.bp
index 21dc2b4..4a783c3 100644
--- a/configstore/Android.bp
+++ b/configstore/Android.bp
@@ -3,5 +3,6 @@
     "1.0",
     "1.0/vts/functional",
     "1.1",
+    "1.1/vts/functional",
     "utils",
 ]
diff --git a/current.txt b/current.txt
index 64fafbf..a5b5930 100644
--- a/current.txt
+++ b/current.txt
@@ -189,6 +189,35 @@
 
 # ABI preserving changes to HALs released in Android O
 
+8a4082dbc7f5eef585dca841b2656ba62d6c7e10e25dd05507ead15d96224f4c android.hardware.broadcastradio@1.0::types
 760485232f6cce07f8bb05e3475509956996b702f77415ee5bff05e2ec5a5bcc android.hardware.dumpstate@1.0::IDumpstateDevice
-78589343d8ee2e1b155acad3fbdc7fcbb6af94491aee968b2383c21627264f8b android.hardware.radio@1.0::IRadioResponse
+1fecfa1609ff9d27ebf761a84b4336efa9d5dac5b241f19a6663f70d8db2c4b1 android.hardware.radio@1.0::IRadioResponse
 28e929b453df3d9f5060af2764e6cdb123ddb893e3e86923c877f6ff7e5f02c9 android.hardware.wifi@1.0::types
+
+# HALs released in Android O MR1
+
+37a00ee36a2e38f9ff87cf71a37a49c13fe194fbed123c6b05c69fc76071f5c9 android.hardware.configstore@1.1::ISurfaceFlingerConfigs
+4b65763663a94a3920134011691f8fbb42ccb7b7795589efddc049a9106047d6 android.hardware.oemlock@1.0::IOemLock
+e02cd3722cb5e8fa51179f5defacb4f7866f903c9c7c51dc01a3148473a71525 android.hardware.oemlock@1.0::types
+9f69e783fa2c482d90b2f799ddd33378a92d22a261983df6b492358e01f4d791 android.hardware.power@1.1::IPower
+574fd9758b7cab4922c72cc5a9f36d1cd48ffd3425fdd776426653280d3d4138 android.hardware.power@1.1::types
+f79edf50a378a9c9bb737f93f205dab91b4c63ea49723afc6f856c138203ea81 android.hardware.radio@1.1::IRadio
+fcc5c8c88b85a9f63fba67d9e674da466c72a98ca287f343fb5721d098713f86 android.hardware.radio@1.1::IRadioIndication
+50f27e8c7ec009d5d4418b2ce8392b940bbf052ecc1d7251285f332485a5ba4e android.hardware.radio@1.1::IRadioResponse
+d8d6bf7b4d36c04ce587df75953c3f723cfbe71c896c1aa8ab6478eae126723d android.hardware.radio@1.1::types
+d8aae01606bfd34bf2fb9a59cadc016f46f318e56cddb8f15a945c5b3c1222bc android.hardware.tetheroffload.config@1.0::IOffloadConfig
+447b00306bc95a7aafec1d660f6f3e9f76ac8bc0353193435e5579ab833da619 android.hardware.tetheroffload.control@1.0::IOffloadControl
+07658829339d75962016e00ed81b005ad29fca7ac12ad3bc3ccd86b08d94c2d3 android.hardware.tetheroffload.control@1.0::ITetheringOffloadCallback
+0df5b0178af15c53cdce8fcf8ca14035e8e08db4fa76fdc12009ddbe0b53626b android.hardware.tetheroffload.control@1.0::types
+b30ef02ef26ff804e2f6acf1201bc141b59e134e6a0338562284491102cb13e3 android.hardware.usb@1.1::IUsb
+13a580e35af01270a1e9774177c51db51d8672e6139ba00851e654e68a4d7dff android.hardware.usb@1.1::IUsbCallback
+f0ed667288908c08fced570bd1f3c4a0f236aa927938e805f0d9fece525da81e android.hardware.usb@1.1::types
+f95a1e85612f2d0d616eacd2eb63c52d10dfa889f165df57697c30e1f47b4785 android.hardware.vibrator@1.1::IVibrator
+246fb9d9e2b4800aeb0adc3cdbaa15d0321ebab54b7bd1ab87da5b67c7b0b064 android.hardware.vibrator@1.1::types
+9bc43413b80cd0c59a022e93da1448dcb82dd10c6dd31932df4659e4bdcb1368 android.hardware.weaver@1.0::IWeaver
+7728b0393a2ed9796537d4165c7d95407e9d8cb447a647b545fdfe06a28689e7 android.hardware.weaver@1.0::types
+bb7c96762d0aa3ddb874c8815bacdd3cbc8fb87ea2f82b928bc29e24a3593055 android.hardware.wifi.offload@1.0::IOffload
+c3354ab0d381a236c12dc486ad4b6bec28c979d26748b4661f12ede36f392808 android.hardware.wifi.offload@1.0::IOffloadCallback
+b18caefefcc765092412285d776234fcf213b73bdf07ae1b67a5f71b2d2464e3 android.hardware.wifi.offload@1.0::types
+c26473e2e4a00af43e28a0ddf9002e5062a7d0940429e5efb6e5513a8abcb75c android.hardware.wifi@1.1::IWifi
+48adfb7259e3816a82a4c394ffaf56fb14628a542295b7a51f1311392d3f8769 android.hardware.wifi@1.1::IWifiChip
diff --git a/drm/1.0/default/Android.mk b/drm/1.0/default/Android.mk
index 0cc6e71..99773be 100644
--- a/drm/1.0/default/Android.mk
+++ b/drm/1.0/default/Android.mk
@@ -42,6 +42,9 @@
 LOCAL_C_INCLUDES := \
   hardware/interfaces/drm
 
+LOCAL_HEADER_LIBRARIES := \
+  media_plugin_headers
+
 # TODO(b/18948909) Some legacy DRM plugins only support 32-bit. They need to be
 # migrated to 64-bit. Once all of a device's legacy DRM plugins support 64-bit,
 # that device can turn on TARGET_ENABLE_MEDIADRM_64 to build this service as
diff --git a/drm/1.0/default/CryptoFactory.h b/drm/1.0/default/CryptoFactory.h
index 6b1d1ff..86130dc 100644
--- a/drm/1.0/default/CryptoFactory.h
+++ b/drm/1.0/default/CryptoFactory.h
@@ -20,7 +20,6 @@
 #include <hidl/Status.h>
 #include <media/hardware/CryptoAPI.h>
 #include <PluginLoader.h>
-#include <media/SharedLibrary.h>
 
 namespace android {
 namespace hardware {
diff --git a/drm/1.0/default/DrmFactory.h b/drm/1.0/default/DrmFactory.h
index 726bf97..32e192d 100644
--- a/drm/1.0/default/DrmFactory.h
+++ b/drm/1.0/default/DrmFactory.h
@@ -20,7 +20,6 @@
 #include <hidl/Status.h>
 #include <media/drm/DrmAPI.h>
 #include <PluginLoader.h>
-#include <media/SharedLibrary.h>
 
 namespace android {
 namespace hardware {
diff --git a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
index e2c9cca..67b2c7d 100644
--- a/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
+++ b/drm/1.0/vts/functional/drm_hal_vendor_test.cpp
@@ -128,7 +128,7 @@
         // Do the same for the crypto factory
         cryptoFactory = VtsTestBase::getService<ICryptoFactory>(name);
         if (cryptoFactory == nullptr) {
-            VtsTestBase::getService<ICryptoFactory>();
+            cryptoFactory = VtsTestBase::getService<ICryptoFactory>();
         }
         ASSERT_NE(cryptoFactory, nullptr);
 
diff --git a/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp b/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
index 3dad3c1..a017404 100644
--- a/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
+++ b/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
@@ -59,7 +59,7 @@
     uint32_t len = 16;
     hidl_vec<int32_t> vec;
     vec.resize(len);
-    std::fill(vec.begin(), vec.end(), 1);
+    std::fill(vec.begin(), vec.end(), 1000);
     for (auto range = ranges.begin(); range != ranges.end(); range++) {
       EXPECT_TRUE(ir->transmit(range->min, vec));
       EXPECT_TRUE(ir->transmit(range->max, vec));
@@ -74,7 +74,6 @@
   vec.resize(len);
   std::fill(vec.begin(), vec.end(), 1);
   EXPECT_FALSE(ir->transmit(-1, vec));
-  EXPECT_FALSE(ir->transmit(0, vec));
 }
 
 int main(int argc, char **argv) {
diff --git a/oemlock/1.0/vts/functional/Android.bp b/oemlock/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..a13b3dc
--- /dev/null
+++ b/oemlock/1.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalOemLockV1_0TargetTest",
+    defaults: ["hidl_defaults"],
+    srcs: ["VtsHalOemLockV1_0TargetTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "libnativehelper",
+        "libutils",
+        "android.hardware.oemlock@1.0",
+    ],
+    static_libs: ["VtsHalHidlTargetTestBase"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp b/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp
new file mode 100644
index 0000000..a924fec
--- /dev/null
+++ b/oemlock/1.0/vts/functional/VtsHalOemLockV1_0TargetTest.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/oemlock/1.0/IOemLock.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+using ::android::hardware::oemlock::V1_0::IOemLock;
+using ::android::hardware::oemlock::V1_0::OemLockStatus;
+using ::android::hardware::oemlock::V1_0::OemLockSecureStatus;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+
+struct OemLockHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+    virtual void SetUp() override {
+        oemlock = ::testing::VtsHalHidlTargetTestBase::getService<IOemLock>();
+        ASSERT_NE(oemlock, nullptr);
+    }
+
+    virtual void TearDown() override {}
+
+    sp<IOemLock> oemlock;
+};
+
+/*
+ * Check the name can be retrieved
+ */
+TEST_F(OemLockHidlTest, GetName) {
+    std::string name;
+    OemLockStatus status;
+
+    bool callbackCalled = false;
+    const auto ret = oemlock->getName([&](OemLockStatus s, hidl_string n) {
+        callbackCalled = true;
+        status = s;
+        name = n.c_str();
+    });
+
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_TRUE(callbackCalled);
+    EXPECT_EQ(status, OemLockStatus::OK);
+    // Any value acceptable
+};
+
+/*
+ * Check the unlock allowed by device state can be queried
+ */
+TEST_F(OemLockHidlTest, QueryUnlockAllowedByDevice) {
+    bool allowed;
+    OemLockStatus status;
+
+    bool callbackCalled = false;
+    const auto ret = oemlock->isOemUnlockAllowedByDevice([&](OemLockStatus s, bool a) {
+        callbackCalled = true;
+        status = s;
+        allowed = a;
+    });
+
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_TRUE(callbackCalled);
+    EXPECT_EQ(status, OemLockStatus::OK);
+    // Any value acceptable
+}
+
+/*
+ * Check unlock allowed by device state can be toggled
+ */
+TEST_F(OemLockHidlTest, AllowedByDeviceCanBeToggled) {
+    bool allowed;
+    OemLockStatus status;
+
+    auto getAllowedCallback = [&](OemLockStatus s, bool a) {
+        status = s;
+        allowed = a;
+    };
+
+    // Get the original state so it can be restored
+    const auto get_ret = oemlock->isOemUnlockAllowedByDevice(getAllowedCallback);
+    ASSERT_TRUE(get_ret.isOk());
+    ASSERT_EQ(status, OemLockStatus::OK);
+    const bool originallyAllowed = allowed;
+
+    // Toggle the state
+    const auto set_ret = oemlock->setOemUnlockAllowedByDevice(!originallyAllowed);
+    ASSERT_TRUE(set_ret.isOk());
+    ASSERT_EQ(set_ret, OemLockStatus::OK);
+    const auto check_set_ret = oemlock->isOemUnlockAllowedByDevice(getAllowedCallback);
+    ASSERT_TRUE(check_set_ret.isOk());
+    ASSERT_EQ(status, OemLockStatus::OK);
+    ASSERT_EQ(allowed, !originallyAllowed);
+
+    // Restore the state
+    const auto restore_ret = oemlock->setOemUnlockAllowedByDevice(originallyAllowed);
+    ASSERT_TRUE(restore_ret.isOk());
+    ASSERT_EQ(restore_ret, OemLockStatus::OK);
+    const auto check_restore_ret = oemlock->isOemUnlockAllowedByDevice(getAllowedCallback);
+    ASSERT_TRUE(check_restore_ret.isOk());
+    ASSERT_EQ(status, OemLockStatus::OK);
+    ASSERT_EQ(allowed, originallyAllowed);
+};
+
+/*
+ * Check the unlock allowed by device state can be queried
+ */
+TEST_F(OemLockHidlTest, QueryUnlockAllowedByCarrier) {
+    bool allowed;
+    OemLockStatus status;
+
+    bool callbackCalled = false;
+    const auto ret = oemlock->isOemUnlockAllowedByCarrier([&](OemLockStatus s, bool a) {
+        callbackCalled = true;
+        status = s;
+        allowed = a;
+    });
+
+    ASSERT_TRUE(ret.isOk());
+    ASSERT_TRUE(callbackCalled);
+    EXPECT_EQ(status, OemLockStatus::OK);
+    // Any value acceptable
+}
+
+/*
+ * Attempt to check unlock allowed by carrier can be toggled
+ *
+ * The implementation may involve a signature which cannot be tested here. That
+ * is a valid implementation so the test will pass. If there is no signature
+ * required, the test will toggle the value.
+ */
+TEST_F(OemLockHidlTest, CarrierUnlock) {
+    const hidl_vec<uint8_t> noSignature = {};
+    bool allowed;
+    OemLockStatus status;
+
+    auto getAllowedCallback = [&](OemLockStatus s, bool a) {
+        status = s;
+        allowed = a;
+    };
+
+    // Get the original state so it can be restored
+    const auto get_ret = oemlock->isOemUnlockAllowedByCarrier(getAllowedCallback);
+    ASSERT_TRUE(get_ret.isOk());
+    ASSERT_EQ(status, OemLockStatus::OK);
+    const bool originallyAllowed = allowed;
+
+    if (originallyAllowed) {
+        // Only applied to locked devices
+        return;
+    }
+
+    // Toggle the state
+    const auto set_ret = oemlock->setOemUnlockAllowedByCarrier(!originallyAllowed, noSignature);
+    ASSERT_TRUE(set_ret.isOk());
+    ASSERT_NE(set_ret, OemLockSecureStatus::FAILED);
+    const auto check_set_ret = oemlock->isOemUnlockAllowedByCarrier(getAllowedCallback);
+    ASSERT_TRUE(check_set_ret.isOk());
+    ASSERT_EQ(status, OemLockStatus::OK);
+
+    if (set_ret == OemLockSecureStatus::INVALID_SIGNATURE) {
+        // Signature is required so we cannot toggle the value in the test, but this is allowed
+        ASSERT_EQ(allowed, originallyAllowed);
+        return;
+    }
+
+    ASSERT_EQ(set_ret, OemLockSecureStatus::OK);
+    ASSERT_EQ(allowed, !originallyAllowed);
+
+    // Restore the state
+    const auto restore_ret = oemlock->setOemUnlockAllowedByCarrier(originallyAllowed, noSignature);
+    ASSERT_TRUE(restore_ret.isOk());
+    ASSERT_EQ(restore_ret, OemLockSecureStatus::OK);
+    const auto check_restore_ret = oemlock->isOemUnlockAllowedByCarrier(getAllowedCallback);
+    ASSERT_TRUE(check_restore_ret.isOk());
+    ASSERT_EQ(status, OemLockStatus::OK);
+    ASSERT_EQ(allowed, originallyAllowed);
+};
diff --git a/oemlock/Android.bp b/oemlock/Android.bp
index bbb3e4b..33f70eb 100644
--- a/oemlock/Android.bp
+++ b/oemlock/Android.bp
@@ -1,4 +1,5 @@
 // This is an autogenerated file, do not edit.
 subdirs = [
     "1.0",
+    "1.0/vts/functional",
 ]
diff --git a/radio/1.0/IRadioResponse.hal b/radio/1.0/IRadioResponse.hal
index 8697e57..9f19169 100644
--- a/radio/1.0/IRadioResponse.hal
+++ b/radio/1.0/IRadioResponse.hal
@@ -1565,6 +1565,7 @@
      *   RadioError:INVALID_MODEM_STATE
      *   RadioError:NO_RESOURCES
      *   RadioError:CANCELLED
+     *   RadioError:MODE_NOT_SUPPORTED
      */
     oneway sendCDMAFeatureCodeResponse(RadioResponseInfo info);
 
diff --git a/radio/1.0/vts/functional/Android.bp b/radio/1.0/vts/functional/Android.bp
index 5403971..8cd823e 100644
--- a/radio/1.0/vts/functional/Android.bp
+++ b/radio/1.0/vts/functional/Android.bp
@@ -70,3 +70,38 @@
         "-g",
     ],
 }
+
+cc_library_static {
+    name: "RadioHidlHalUtilsBase",
+    srcs : [
+        "radio_hidl_hal_test.cpp",
+        "radio_response.cpp"
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "libnativehelper",
+        "libutils",
+        "android.hardware.radio@1.0",
+    ],
+    static_libs: ["VtsHalHidlTargetTestBase"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
+
+cc_library_static {
+    name: "RadioVtsTestUtilBase",
+    srcs : [
+        "vts_test_util.cpp"
+    ],
+}
+
+cc_library_headers {
+    name: "radio.util.header@1.0",
+    export_include_dirs: ["."],
+}
\ No newline at end of file
diff --git a/radio/1.0/vts/functional/VtsHalRadioV1_0TargetTest.cpp b/radio/1.0/vts/functional/VtsHalRadioV1_0TargetTest.cpp
index 59881ef..3448494 100644
--- a/radio/1.0/vts/functional/VtsHalRadioV1_0TargetTest.cpp
+++ b/radio/1.0/vts/functional/VtsHalRadioV1_0TargetTest.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 int main(int argc, char** argv) {
     ::testing::AddGlobalTestEnvironment(new RadioHidlEnvironment);
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp b/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp
index 14d14d4..a81861d 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_cell_broadcast.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 using namespace ::android::hardware::radio::V1_0;
 
@@ -123,7 +123,8 @@
 
     if (cardStatus.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckGeneralError() ||
-                    radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS);
+                    radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS ||
+                    radioRsp->rspInfo.error == RadioError::NONE);
     }
 }
 
@@ -140,7 +141,7 @@
     EXPECT_EQ(serial, radioRsp->rspInfo.serial);
 
     if (cardStatus.cardState == CardState::ABSENT) {
-        ASSERT_TRUE(CheckGeneralError());
+        ASSERT_TRUE(CheckGeneralError() || radioRsp->rspInfo.error == RadioError::NONE);
     }
 }
 
@@ -159,7 +160,8 @@
 
     if (cardStatus.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckGeneralError() ||
-                    radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS);
+                    radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS ||
+                    radioRsp->rspInfo.error == RadioError::NONE);
     }
 }
 
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_data.cpp b/radio/1.0/vts/functional/radio_hidl_hal_data.cpp
index 108676b..35d97ee 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_data.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_data.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 using namespace ::android::hardware::radio::V1_0;
 
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp
index 4841185..9e003e2 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_icc.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 /*
  * Test IRadio.getIccCardStatus() for the response returned.
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp b/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp
index 16465c7..c1834c5 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_ims.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 using namespace ::android::hardware::radio::V1_0;
 
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
index f965296..13c23a8 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 /*
  * Test IRadio.getSignalStrength() for the response returned.
@@ -184,7 +184,7 @@
     EXPECT_EQ(serial, radioRsp->rspInfo.serial);
 
     if (cardStatus.cardState == CardState::ABSENT) {
-        EXPECT_EQ(radioRsp->rspInfo.error, RadioError::NONE);
+        ASSERT_TRUE(CheckGeneralError() || radioRsp->rspInfo.error == RadioError::NONE);
     }
 }
 
@@ -216,7 +216,7 @@
     EXPECT_EQ(serial, radioRsp->rspInfo.serial);
 
     if (cardStatus.cardState == CardState::ABSENT) {
-        EXPECT_EQ(radioRsp->rspInfo.error, RadioError::NONE);
+        ASSERT_TRUE(CheckGeneralError() || radioRsp->rspInfo.error == RadioError::NONE);
     }
 }
 
@@ -707,7 +707,8 @@
 
     if (cardStatus.cardState == CardState::ABSENT) {
         ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::RADIO_NOT_AVAILABLE || CheckOEMError() ||
-                    radioRsp->rspInfo.error == RadioError::INTERNAL_ERR);
+                    radioRsp->rspInfo.error == RadioError::INTERNAL_ERR ||
+                    radioRsp->rspInfo.error == RadioError::NONE);
     }
 }
 
@@ -747,7 +748,7 @@
     EXPECT_EQ(serial, radioRsp->rspInfo.serial);
 
     if (cardStatus.cardState == CardState::ABSENT) {
-        EXPECT_EQ(radioRsp->rspInfo.error, RadioError::NONE);
+        ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE || CheckGeneralError());
   }
 
   /* Reset back to no carrier restriction */
@@ -761,7 +762,7 @@
   EXPECT_EQ(serial, radioRsp->rspInfo.serial);
 
   if (cardStatus.cardState == CardState::ABSENT) {
-      EXPECT_EQ(radioRsp->rspInfo.error, RadioError::NONE);
+      ASSERT_TRUE(radioRsp->rspInfo.error == RadioError::NONE || CheckGeneralError());
   }
 }
 
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp b/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp
index 9aa7663..271a23a 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_sms.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 using namespace ::android::hardware::radio::V1_0;
 
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp b/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp
index 6ff0330..9e51df4 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_stk.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 using namespace ::android::hardware::radio::V1_0;
 
@@ -37,7 +37,8 @@
         std::cout << static_cast<int>(radioRsp->rspInfo.error) << std::endl;
         ASSERT_TRUE(CheckGeneralError() ||
                     radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS ||
-                    radioRsp->rspInfo.error == RadioError::NONE);
+                    radioRsp->rspInfo.error == RadioError::NONE ||
+                    radioRsp->rspInfo.error == RadioError::MODEM_ERR);
     }
 
     // Test with sending random string
@@ -54,7 +55,8 @@
         std::cout << static_cast<int>(radioRsp->rspInfo.error) << std::endl;
         ASSERT_TRUE(CheckGeneralError() ||
                     radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS ||
-                    radioRsp->rspInfo.error == RadioError::NONE);
+                    radioRsp->rspInfo.error == RadioError::NONE ||
+                    radioRsp->rspInfo.error == RadioError::MODEM_ERR);
     }
 }
 
@@ -153,7 +155,8 @@
 
     if (cardStatus.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckGeneralError() ||
-                    radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS);
+                    radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS ||
+                    radioRsp->rspInfo.error == RadioError::MODEM_ERR);
     }
 
     // Test with sending random string
@@ -168,6 +171,7 @@
 
     if (cardStatus.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckGeneralError() ||
-                    radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS);
+                    radioRsp->rspInfo.error == RadioError::INVALID_ARGUMENTS ||
+                    radioRsp->rspInfo.error == RadioError::MODEM_ERR);
     }
 }
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_test.cpp b/radio/1.0/vts/functional/radio_hidl_hal_test.cpp
index b957c6e..2fa2827 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 void RadioHidlTest::SetUp() {
     radio =
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_utils.h b/radio/1.0/vts/functional/radio_hidl_hal_utils_v1_0.h
similarity index 99%
rename from radio/1.0/vts/functional/radio_hidl_hal_utils.h
rename to radio/1.0/vts/functional/radio_hidl_hal_utils_v1_0.h
index a0d7f70..c126da4 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_utils.h
+++ b/radio/1.0/vts/functional/radio_hidl_hal_utils_v1_0.h
@@ -26,7 +26,7 @@
 #include <android/hardware/radio/1.0/IRadioResponse.h>
 #include <android/hardware/radio/1.0/types.h>
 
-#include <vts_test_util.h>
+#include "vts_test_util.h"
 
 using ::android::hardware::radio::V1_0::ActivityStatsInfo;
 using ::android::hardware::radio::V1_0::AppType;
@@ -90,7 +90,7 @@
 
 /* Callback class for radio response */
 class RadioResponse : public IRadioResponse {
-   private:
+   protected:
     RadioHidlTest& parent;
 
    public:
@@ -442,7 +442,7 @@
 
 // The main test class for Radio HIDL.
 class RadioHidlTest : public ::testing::VtsHalHidlTargetTestBase {
-   private:
+   protected:
     std::mutex mtx;
     std::condition_variable cv;
     int count;
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
index d57360f..f5be572 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_voice.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 /*
  * Test IRadio.getCurrentCalls() for the response returned.
@@ -214,7 +214,8 @@
 
     if (cardStatus.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckGeneralError() || radioRsp->rspInfo.error == RadioError::INVALID_STATE ||
-                    radioRsp->rspInfo.error == RadioError::MODEM_ERR);
+                    radioRsp->rspInfo.error == RadioError::MODEM_ERR ||
+                    radioRsp->rspInfo.error == RadioError::NONE);
     }
 }
 
@@ -371,7 +372,8 @@
                     radioRsp->rspInfo.error == RadioError::NONE ||
                     radioRsp->rspInfo.error == RadioError::INVALID_CALL_ID ||
                     radioRsp->rspInfo.error == RadioError::INVALID_MODEM_STATE ||
-                    radioRsp->rspInfo.error == RadioError::MODEM_ERR);
+                    radioRsp->rspInfo.error == RadioError::MODEM_ERR ||
+                    radioRsp->rspInfo.error == RadioError::MODE_NOT_SUPPORTED);
     }
 }
 
diff --git a/radio/1.0/vts/functional/radio_response.cpp b/radio/1.0/vts/functional/radio_response.cpp
index ef887eb..434d488 100644
--- a/radio/1.0/vts/functional/radio_response.cpp
+++ b/radio/1.0/vts/functional/radio_response.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <radio_hidl_hal_utils.h>
+#include <radio_hidl_hal_utils_v1_0.h>
 
 CardStatus cardStatus;
 
diff --git a/radio/1.0/vts/functional/sap_hidl_hal_utils.h b/radio/1.0/vts/functional/sap_hidl_hal_utils.h
index fe93a4d..7126b06 100644
--- a/radio/1.0/vts/functional/sap_hidl_hal_utils.h
+++ b/radio/1.0/vts/functional/sap_hidl_hal_utils.h
@@ -25,7 +25,7 @@
 #include <android/hardware/radio/1.0/ISapCallback.h>
 #include <android/hardware/radio/1.0/types.h>
 
-#include <vts_test_util.h>
+#include "vts_test_util.h"
 
 using namespace ::android::hardware::radio::V1_0;
 
diff --git a/radio/1.1/types.hal b/radio/1.1/types.hal
index a8d836c..93d5d44 100644
--- a/radio/1.1/types.hal
+++ b/radio/1.1/types.hal
@@ -176,26 +176,6 @@
     vec<CellInfo> networkInfos;             // List of network information as CellInfo
 };
 
-struct ImsiEncryptionInfo {
-    string mcc;                   // MCC of the Carrier.
-    string mnc;                   // MNC of the Carrier.
-    vec<uint8_t> carrierKey;      // Carrier specific key to be used for encryption. It must
-                                  // be opaque to the framework. This is the byte-stream
-                                  // representation of the key. This is an external encoded
-                                  // form for the key used when a standard representation of
-                                  // the key is needed outside the Java Virtual Machine, as
-                                  // when transmitting the key to some other party.
-                                  // The key is encoded according to a standard format
-                                  // (such as X.509 SubjectPublicKeyInfo or PKCS#8), and is
-                                  // returned using the getEncoded method as defined on the
-                                  // java.security.Key interface.
-    string keyIdentifier;         // This is an opaque value we're given by the carrier
-                                  // and is returned to the carrier. This is used by the server to
-                                  // help it locate the private key to decrypt the permanent
-                                  // identity.
-    int64_t expirationTime;       // date-time in UTC when the key will expire.
-};
-
 struct KeepaliveRequest {
     KeepaliveType type;                     // The format of the keepalive packet
     vec<uint8_t> sourceAddress;             // source address with type = family, in network
@@ -216,3 +196,23 @@
     int32_t sessionHandle;                  // the sessionHandle provided by the api
     KeepaliveStatusCode code;               // status for the given keepalive
 };
+
+struct ImsiEncryptionInfo {
+    string mcc;                   // MCC of the Carrier.
+    string mnc;                   // MNC of the Carrier.
+    vec<uint8_t> carrierKey;      // Carrier specific key to be used for encryption. It must
+                                  // be opaque to the framework. This is the byte-stream
+                                  // representation of the key. This is an external encoded
+                                  // form for the key used when a standard representation of
+                                  // the key is needed outside the Java Virtual Machine, as
+                                  // when transmitting the key to some other party.
+                                  // The key is encoded according to a standard format
+                                  // (such as X.509 SubjectPublicKeyInfo or PKCS#8), and is
+                                  // returned using the getEncoded method as defined on the
+                                  // java.security.Key interface.
+    string keyIdentifier;         // This is an opaque value we're given by the carrier
+                                  // and is returned to the carrier. This is used by the server to
+                                  // help it locate the private key to decrypt the permanent
+                                  // identity.
+    int64_t expirationTime;       // date-time in UTC when the key will expire.
+};
diff --git a/radio/1.1/vts/functional/Android.bp b/radio/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..14a2544
--- /dev/null
+++ b/radio/1.1/vts/functional/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalRadioV1_1TargetTest",
+    defaults: ["hidl_defaults"],
+    srcs: ["radio_hidl_hal_api.cpp",
+           "radio_hidl_hal_test.cpp",
+           "radio_response.cpp",
+           "VtsHalRadioV1_1TargetTest.cpp"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "libnativehelper",
+        "libutils",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.0",
+    ],
+    static_libs: ["VtsHalHidlTargetTestBase",
+                  "RadioHidlHalUtilsBase",
+                  "RadioVtsTestUtilBase"],
+    header_libs: [
+        "radio.util.header@1.0",
+    ],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/radio/1.1/vts/functional/VtsHalRadioV1_1TargetTest.cpp b/radio/1.1/vts/functional/VtsHalRadioV1_1TargetTest.cpp
new file mode 100644
index 0000000..09351c8
--- /dev/null
+++ b/radio/1.1/vts/functional/VtsHalRadioV1_1TargetTest.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_hidl_hal_utils_v1_1.h>
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(new RadioHidlEnvironment);
+    ::testing::InitGoogleTest(&argc, argv);
+
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+
+    return status;
+}
\ No newline at end of file
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
new file mode 100644
index 0000000..666a317
--- /dev/null
+++ b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_hidl_hal_utils_v1_1.h>
+
+/*
+ * Test IRadio.setSimCardPower() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_1, setSimCardPower_1_1) {
+    int serial = GetRandomSerialNumber();
+
+    radio_v1_1->setSimCardPower_1_1(serial, CardPowerState::POWER_DOWN);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_1->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_1->rspInfo.serial);
+
+    if (cardStatus.cardState == CardState::ABSENT) {
+        ASSERT_TRUE(radioRsp_v1_1->rspInfo.error == RadioError::NONE ||
+                    radioRsp_v1_1->rspInfo.error == RadioError::REQUEST_NOT_SUPPORTED ||
+                    radioRsp_v1_1->rspInfo.error == RadioError::INVALID_ARGUMENTS ||
+                    radioRsp_v1_1->rspInfo.error == RadioError::RADIO_NOT_AVAILABLE);
+    }
+}
\ No newline at end of file
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_test.cpp b/radio/1.1/vts/functional/radio_hidl_hal_test.cpp
new file mode 100644
index 0000000..164128b
--- /dev/null
+++ b/radio/1.1/vts/functional/radio_hidl_hal_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_hidl_hal_utils_v1_1.h>
+
+void RadioHidlTest_v1_1::SetUp() {
+    radio_v1_1 =
+        ::testing::VtsHalHidlTargetTestBase::getService<::android::hardware::radio::V1_1::IRadio>(
+            hidl_string(RADIO_SERVICE_NAME));
+    ASSERT_NE(radio_v1_1, nullptr);
+
+    radioRsp_v1_1 = new RadioResponse_v1_1(*this);
+    ASSERT_NE(radioRsp_v1_1, nullptr);
+
+    count = 0;
+
+    radioInd_v1_1 = NULL;
+    radio_v1_1->setResponseFunctions(radioRsp_v1_1, radioInd_v1_1);
+
+    int serial = GetRandomSerialNumber();
+    radio_v1_1->getIccCardStatus(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_1->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_1->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_1->rspInfo.error);
+}
\ No newline at end of file
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_utils_v1_1.h b/radio/1.1/vts/functional/radio_hidl_hal_utils_v1_1.h
new file mode 100644
index 0000000..ae72d8f
--- /dev/null
+++ b/radio/1.1/vts/functional/radio_hidl_hal_utils_v1_1.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/radio/1.1/IRadio.h>
+#include <android/hardware/radio/1.1/IRadioIndication.h>
+#include <android/hardware/radio/1.1/IRadioResponse.h>
+#include <android/hardware/radio/1.1/types.h>
+
+#include "radio_hidl_hal_utils_v1_0.h"
+
+using namespace ::android::hardware::radio::V1_1;
+
+class RadioHidlTest_v1_1;
+
+/* Callback class for radio response v1_1*/
+class RadioResponse_v1_1 : public RadioResponse {
+   protected:
+    RadioHidlTest_v1_1& parent_v1_1;
+
+   public:
+    RadioResponse_v1_1(RadioHidlTest_v1_1& parent_v1_1);
+    virtual ~RadioResponse_v1_1() = default;
+
+    /* 1.1 Api */
+    Return<void> setCarrierInfoForImsiEncryptionResponse(const RadioResponseInfo& info);
+
+    Return<void> setSimCardPowerResponse_1_1(const RadioResponseInfo& info);
+
+    Return<void> startNetworkScanResponse(const RadioResponseInfo& info);
+
+    Return<void> stopNetworkScanResponse(const RadioResponseInfo& info);
+};
+
+// The main test class for Radio HIDL.
+class RadioHidlTest_v1_1 : public RadioHidlTest {
+   public:
+    virtual void SetUp() override;
+    sp<::android::hardware::radio::V1_1::IRadio> radio_v1_1;
+    sp<RadioResponse_v1_1> radioRsp_v1_1;
+    sp<::android::hardware::radio::V1_1::IRadioIndication> radioInd_v1_1;
+};
\ No newline at end of file
diff --git a/radio/1.1/vts/functional/radio_response.cpp b/radio/1.1/vts/functional/radio_response.cpp
new file mode 100644
index 0000000..c5c8fd7
--- /dev/null
+++ b/radio/1.1/vts/functional/radio_response.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <radio_hidl_hal_utils_v1_1.h>
+
+RadioResponse_v1_1::RadioResponse_v1_1(RadioHidlTest_v1_1& parent)
+    : RadioResponse(parent), parent_v1_1(parent) {}
+
+/* 1.1 Apis */
+Return<void> RadioResponse_v1_1::setCarrierInfoForImsiEncryptionResponse(
+    const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_1::setSimCardPowerResponse_1_1(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_1.notify();
+    return Void();
+}
+
+Return<void> RadioResponse_v1_1::startNetworkScanResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_1::stopNetworkScanResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
\ No newline at end of file
diff --git a/radio/Android.bp b/radio/Android.bp
index dbeca0c..0acb2ee 100644
--- a/radio/Android.bp
+++ b/radio/Android.bp
@@ -3,5 +3,6 @@
     "1.0",
     "1.0/vts/functional",
     "1.1",
+    "1.1/vts/functional",
     "deprecated/1.0",
 ]
diff --git a/sensors/1.0/default/Android.bp b/sensors/1.0/default/Android.bp
index 8144590..4bbafa6 100644
--- a/sensors/1.0/default/Android.bp
+++ b/sensors/1.0/default/Android.bp
@@ -38,6 +38,9 @@
         "android.hardware.sensors@1.0",
     ],
     local_include_dirs: ["include/sensors"],
+    export_shared_lib_headers: [
+        "libhardware",
+    ],
 }
 
 
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
index 4842946..3006508 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -543,7 +543,7 @@
 };
 
 const Vec3NormChecker SensorsHidlTest::sAccelNormChecker(
-        Vec3NormChecker::byNominal(GRAVITY_EARTH, 0.5f/*m/s^2*/));
+        Vec3NormChecker::byNominal(GRAVITY_EARTH, 1.0f/*m/s^2*/));
 const Vec3NormChecker SensorsHidlTest::sGyroNormChecker(
         Vec3NormChecker::byNominal(0.f, 0.1f/*rad/s*/));
 
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index b454a06..2d6679f 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -17,10 +17,12 @@
 cc_library_static {
     name: "VtsHalWifiV1_0TargetTestUtil",
     srcs: [
-
         "wifi_hidl_call_util_selftest.cpp",
         "wifi_hidl_test.cpp",
         "wifi_hidl_test_utils.cpp"],
+    export_include_dirs: [
+        "."
+    ],
     shared_libs: [
         "libbase",
         "liblog",
diff --git a/wifi/1.1/Android.bp b/wifi/1.1/Android.bp
new file mode 100644
index 0000000..f991fa5
--- /dev/null
+++ b/wifi/1.1/Android.bp
@@ -0,0 +1,68 @@
+// This file is autogenerated by hidl-gen. Do not edit manually.
+
+filegroup {
+    name: "android.hardware.wifi@1.1_hal",
+    srcs: [
+        "IWifi.hal",
+        "IWifiChip.hal",
+    ],
+}
+
+genrule {
+    name: "android.hardware.wifi@1.1_genc++",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-sources -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.wifi@1.1",
+    srcs: [
+        ":android.hardware.wifi@1.1_hal",
+    ],
+    out: [
+        "android/hardware/wifi/1.1/WifiAll.cpp",
+        "android/hardware/wifi/1.1/WifiChipAll.cpp",
+    ],
+}
+
+genrule {
+    name: "android.hardware.wifi@1.1_genc++_headers",
+    tools: ["hidl-gen"],
+    cmd: "$(location hidl-gen) -o $(genDir) -Lc++-headers -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.wifi@1.1",
+    srcs: [
+        ":android.hardware.wifi@1.1_hal",
+    ],
+    out: [
+        "android/hardware/wifi/1.1/IWifi.h",
+        "android/hardware/wifi/1.1/IHwWifi.h",
+        "android/hardware/wifi/1.1/BnHwWifi.h",
+        "android/hardware/wifi/1.1/BpHwWifi.h",
+        "android/hardware/wifi/1.1/BsWifi.h",
+        "android/hardware/wifi/1.1/IWifiChip.h",
+        "android/hardware/wifi/1.1/IHwWifiChip.h",
+        "android/hardware/wifi/1.1/BnHwWifiChip.h",
+        "android/hardware/wifi/1.1/BpHwWifiChip.h",
+        "android/hardware/wifi/1.1/BsWifiChip.h",
+    ],
+}
+
+cc_library_shared {
+    name: "android.hardware.wifi@1.1",
+    defaults: ["hidl-module-defaults"],
+    generated_sources: ["android.hardware.wifi@1.1_genc++"],
+    generated_headers: ["android.hardware.wifi@1.1_genc++_headers"],
+    export_generated_headers: ["android.hardware.wifi@1.1_genc++_headers"],
+    vendor_available: true,
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "liblog",
+        "libutils",
+        "libcutils",
+        "android.hardware.wifi@1.0",
+    ],
+    export_shared_lib_headers: [
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libutils",
+        "android.hardware.wifi@1.0",
+    ],
+}
diff --git a/wifi/1.1/Android.mk b/wifi/1.1/Android.mk
new file mode 100644
index 0000000..fbc79ca
--- /dev/null
+++ b/wifi/1.1/Android.mk
@@ -0,0 +1,116 @@
+# This file is autogenerated by hidl-gen. Do not edit manually.
+
+LOCAL_PATH := $(call my-dir)
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi-V1.1-java
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_JAVA_LIBRARIES := \
+    android.hardware.wifi-V1.0-java \
+    android.hidl.base-V1.0-java \
+
+
+#
+# Build IWifi.hal
+#
+GEN := $(intermediates)/android/hardware/wifi/V1_1/IWifi.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IWifi.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.wifi@1.1::IWifi
+
+$(GEN): $(LOCAL_PATH)/IWifi.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IWifiChip.hal
+#
+GEN := $(intermediates)/android/hardware/wifi/V1_1/IWifiChip.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IWifiChip.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.wifi@1.1::IWifiChip
+
+$(GEN): $(LOCAL_PATH)/IWifiChip.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_JAVA_LIBRARY)
+
+
+################################################################################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.wifi-V1.1-java-static
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+
+intermediates := $(call local-generated-sources-dir, COMMON)
+
+HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android.hardware.wifi-V1.0-java-static \
+    android.hidl.base-V1.0-java-static \
+
+
+#
+# Build IWifi.hal
+#
+GEN := $(intermediates)/android/hardware/wifi/V1_1/IWifi.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IWifi.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.wifi@1.1::IWifi
+
+$(GEN): $(LOCAL_PATH)/IWifi.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build IWifiChip.hal
+#
+GEN := $(intermediates)/android/hardware/wifi/V1_1/IWifiChip.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/IWifiChip.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.wifi@1.1::IWifiChip
+
+$(GEN): $(LOCAL_PATH)/IWifiChip.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/wifi/1.1/IWifi.hal b/wifi/1.1/IWifi.hal
new file mode 100644
index 0000000..bd48f57
--- /dev/null
+++ b/wifi/1.1/IWifi.hal
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.1;
+
+import @1.0::IWifi;
+
+/**
+ * This is the root of the HAL module and is the interface returned when
+ * loading an implementation of the Wi-Fi HAL. There must be at most one
+ * module loaded in the system.
+ * IWifi.getChip() may return either a @1.0::IWifiChip or @1.1::IWifiChip.
+ */
+interface IWifi extends @1.0::IWifi {
+};
diff --git a/wifi/1.1/IWifiChip.hal b/wifi/1.1/IWifiChip.hal
new file mode 100644
index 0000000..7275412
--- /dev/null
+++ b/wifi/1.1/IWifiChip.hal
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.1;
+
+import @1.0::IWifiChip;
+import @1.0::WifiStatus;
+
+/**
+ * Interface that represents a chip that must be configured as a single unit.
+ * The HAL/driver/firmware will be responsible for determining which phy is used
+ * to perform operations like NAN, RTT, etc.
+ */
+interface IWifiChip extends @1.0::IWifiChip {
+  /**
+   * Capabilities exposed by this chip.
+   */
+  enum ChipCapabilityMask : @1.0::IWifiChip.ChipCapabilityMask {
+    /**
+     * Set/Reset Tx Power limits.
+     */
+    SET_TX_POWER_LIMIT = 1 << 8
+  };
+
+  /**
+   * API to set TX power limit.
+   * This is used for meeting SAR requirements while making VOIP calls for
+   * example.
+   *
+   * @param powerInDbm Power level in dBm.
+   * @return status WifiStatus of the operation.
+   *         Possible status codes:
+   *         |WifiStatusCode.SUCCESS|,
+   *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+   *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+   *         |WifiStatusCode.NOT_AVAILABLE|,
+   *         |WifiStatusCode.UNKNOWN|
+   */
+  setTxPowerLimit(int32_t powerInDbm) generates (WifiStatus status);
+
+  /**
+   * API to reset TX power limit.
+   * This is used to set the power back to default values.
+   *
+   * @return status WifiStatus of the operation.
+   *         Possible status codes:
+   *         |WifiStatusCode.SUCCESS|,
+   *         |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+   *         |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+   *         |WifiStatusCode.NOT_AVAILABLE|,
+   *         |WifiStatusCode.UNKNOWN|
+   */
+  resetTxPowerLimit() generates (WifiStatus status);
+};
diff --git a/wifi/1.0/default/Android.mk b/wifi/1.1/default/Android.mk
similarity index 97%
rename from wifi/1.0/default/Android.mk
rename to wifi/1.1/default/Android.mk
index fe33e08..5758422 100644
--- a/wifi/1.0/default/Android.mk
+++ b/wifi/1.1/default/Android.mk
@@ -38,6 +38,7 @@
     wifi_status_util.cpp
 LOCAL_SHARED_LIBRARIES := \
     android.hardware.wifi@1.0 \
+    android.hardware.wifi@1.1 \
     libbase \
     libcutils \
     libhidlbase \
diff --git a/wifi/1.0/default/THREADING.README b/wifi/1.1/default/THREADING.README
similarity index 100%
rename from wifi/1.0/default/THREADING.README
rename to wifi/1.1/default/THREADING.README
diff --git a/wifi/1.0/default/android.hardware.wifi@1.0-service.rc b/wifi/1.1/default/android.hardware.wifi@1.0-service.rc
similarity index 100%
rename from wifi/1.0/default/android.hardware.wifi@1.0-service.rc
rename to wifi/1.1/default/android.hardware.wifi@1.0-service.rc
diff --git a/wifi/1.0/default/hidl_callback_util.h b/wifi/1.1/default/hidl_callback_util.h
similarity index 98%
rename from wifi/1.0/default/hidl_callback_util.h
rename to wifi/1.1/default/hidl_callback_util.h
index b7100c8..fb13622 100644
--- a/wifi/1.0/default/hidl_callback_util.h
+++ b/wifi/1.1/default/hidl_callback_util.h
@@ -51,7 +51,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace hidl_callback_util {
 template <typename CallbackType>
@@ -114,7 +114,7 @@
 
 }  // namespace hidl_callback_util
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/hidl_return_util.h b/wifi/1.1/default/hidl_return_util.h
similarity index 97%
rename from wifi/1.0/default/hidl_return_util.h
rename to wifi/1.1/default/hidl_return_util.h
index 3f6364b..2f95c23 100644
--- a/wifi/1.0/default/hidl_return_util.h
+++ b/wifi/1.1/default/hidl_return_util.h
@@ -23,9 +23,10 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace hidl_return_util {
+using namespace android::hardware::wifi::V1_0;
 
 /**
  * These utility functions are used to invoke a method on the provided
@@ -106,7 +107,7 @@
 
 }  // namespace hidl_util
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.1/default/hidl_struct_util.cpp
similarity index 99%
rename from wifi/1.0/default/hidl_struct_util.cpp
rename to wifi/1.1/default/hidl_struct_util.cpp
index fa0279b..e40a7d8 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.1/default/hidl_struct_util.cpp
@@ -22,7 +22,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace hidl_struct_util {
 
@@ -2177,7 +2177,7 @@
 }
 }  // namespace hidl_struct_util
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/hidl_struct_util.h b/wifi/1.1/default/hidl_struct_util.h
similarity index 98%
rename from wifi/1.0/default/hidl_struct_util.h
rename to wifi/1.1/default/hidl_struct_util.h
index c04d92f..a04f636 100644
--- a/wifi/1.0/default/hidl_struct_util.h
+++ b/wifi/1.1/default/hidl_struct_util.h
@@ -32,9 +32,10 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace hidl_struct_util {
+using namespace android::hardware::wifi::V1_0;
 
 // Chip conversion methods.
 bool convertLegacyFeaturesToHidlChipCapabilities(
@@ -161,7 +162,7 @@
     std::vector<RttResult>* hidl_results);
 }  // namespace hidl_struct_util
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/hidl_sync_util.cpp b/wifi/1.1/default/hidl_sync_util.cpp
similarity index 96%
rename from wifi/1.0/default/hidl_sync_util.cpp
rename to wifi/1.1/default/hidl_sync_util.cpp
index 7d47f2f..ba18e34 100644
--- a/wifi/1.0/default/hidl_sync_util.cpp
+++ b/wifi/1.1/default/hidl_sync_util.cpp
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace hidl_sync_util {
 
@@ -33,7 +33,7 @@
 
 }  // namespace hidl_sync_util
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/hidl_sync_util.h b/wifi/1.1/default/hidl_sync_util.h
similarity index 96%
rename from wifi/1.0/default/hidl_sync_util.h
rename to wifi/1.1/default/hidl_sync_util.h
index 6631e55..0e882df 100644
--- a/wifi/1.0/default/hidl_sync_util.h
+++ b/wifi/1.1/default/hidl_sync_util.h
@@ -24,13 +24,13 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace hidl_sync_util {
 std::unique_lock<std::recursive_mutex> acquireGlobalLock();
 }  // namespace hidl_sync_util
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/service.cpp b/wifi/1.1/default/service.cpp
similarity index 91%
rename from wifi/1.0/default/service.cpp
rename to wifi/1.1/default/service.cpp
index 059304e..b3fcd50 100644
--- a/wifi/1.0/default/service.cpp
+++ b/wifi/1.1/default/service.cpp
@@ -32,8 +32,8 @@
   configureRpcThreadpool(1, true /* callerWillJoin */);
 
   // Setup hwbinder service
-  android::sp<android::hardware::wifi::V1_0::IWifi> service =
-      new android::hardware::wifi::V1_0::implementation::Wifi();
+  android::sp<android::hardware::wifi::V1_1::IWifi> service =
+      new android::hardware::wifi::V1_1::implementation::Wifi();
   CHECK_EQ(service->registerAsService(), android::NO_ERROR)
       << "Failed to register wifi HAL";
 
diff --git a/wifi/1.0/default/wifi.cpp b/wifi/1.1/default/wifi.cpp
similarity index 99%
rename from wifi/1.0/default/wifi.cpp
rename to wifi/1.1/default/wifi.cpp
index b48844e..4ed1f55 100644
--- a/wifi/1.0/default/wifi.cpp
+++ b/wifi/1.1/default/wifi.cpp
@@ -28,7 +28,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -195,7 +195,7 @@
   return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi.h b/wifi/1.1/default/wifi.h
similarity index 93%
rename from wifi/1.0/default/wifi.h
rename to wifi/1.1/default/wifi.h
index c6fa84c..1ade2d8 100644
--- a/wifi/1.0/default/wifi.h
+++ b/wifi/1.1/default/wifi.h
@@ -20,7 +20,7 @@
 #include <functional>
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifi.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
 #include <utils/Looper.h>
 
 #include "hidl_callback_util.h"
@@ -31,13 +31,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
+using namespace android::hardware::wifi::V1_0;
 
 /**
  * Root HIDL interface object used to control the Wifi HAL.
  */
-class Wifi : public IWifi {
+class Wifi : public V1_1::IWifi {
  public:
   Wifi();
 
@@ -79,7 +80,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_ap_iface.cpp b/wifi/1.1/default/wifi_ap_iface.cpp
similarity index 98%
rename from wifi/1.0/default/wifi_ap_iface.cpp
rename to wifi/1.1/default/wifi_ap_iface.cpp
index e2beec2..150a6cc 100644
--- a/wifi/1.0/default/wifi_ap_iface.cpp
+++ b/wifi/1.1/default/wifi_ap_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -100,7 +100,7 @@
   return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
 }
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_ap_iface.h b/wifi/1.1/default/wifi_ap_iface.h
similarity index 94%
rename from wifi/1.0/default/wifi_ap_iface.h
rename to wifi/1.1/default/wifi_ap_iface.h
index efc168a..608fe6b 100644
--- a/wifi/1.0/default/wifi_ap_iface.h
+++ b/wifi/1.1/default/wifi_ap_iface.h
@@ -25,13 +25,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
+using namespace android::hardware::wifi::V1_0;
 
 /**
  * HIDL interface object used to control a AP Iface instance.
  */
-class WifiApIface : public IWifiApIface {
+class WifiApIface : public V1_0::IWifiApIface {
  public:
   WifiApIface(const std::string& ifname,
               const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -63,7 +64,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_chip.cpp b/wifi/1.1/default/wifi_chip.cpp
similarity index 96%
rename from wifi/1.0/default/wifi_chip.cpp
rename to wifi/1.1/default/wifi_chip.cpp
index 770c83f..87985c0 100644
--- a/wifi/1.0/default/wifi_chip.cpp
+++ b/wifi/1.1/default/wifi_chip.cpp
@@ -46,7 +46,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -343,6 +343,23 @@
                          enable);
 }
 
+Return<void> WifiChip::setTxPowerLimit(
+    int32_t powerInDbm, setTxPowerLimit_cb hidl_status_cb) {
+  return validateAndCall(this,
+                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                         &WifiChip::setTxPowerLimitInternal,
+                         hidl_status_cb,
+                         powerInDbm);
+}
+
+Return<void> WifiChip::resetTxPowerLimit(
+    resetTxPowerLimit_cb hidl_status_cb) {
+  return validateAndCall(this,
+                         WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+                         &WifiChip::resetTxPowerLimitInternal,
+                         hidl_status_cb);
+}
+
 void WifiChip::invalidateAndRemoveAllIfaces() {
   invalidateAndClear(ap_iface_);
   invalidateAndClear(nan_iface_);
@@ -801,6 +818,18 @@
   return createWifiStatusFromLegacyError(legacy_status);
 }
 
+WifiStatus WifiChip::setTxPowerLimitInternal(int32_t /* powerInDbm */) {
+  // TODO(b/62437848): Implement this method once we are ready with the
+  // header changes in legacy HAL.
+  return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
+WifiStatus WifiChip::resetTxPowerLimitInternal() {
+  // TODO(b/62437848): Implement this method once we are ready with the
+  // header changes in legacy HAL.
+  return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
+}
+
 WifiStatus WifiChip::handleChipConfiguration(ChipModeId mode_id) {
   // If the chip is already configured in a different mode, stop
   // the legacy HAL and then start it after firmware mode change.
@@ -869,7 +898,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_chip.h b/wifi/1.1/default/wifi_chip.h
similarity index 95%
rename from wifi/1.0/default/wifi_chip.h
rename to wifi/1.1/default/wifi_chip.h
index 406938c..b7dde50 100644
--- a/wifi/1.0/default/wifi_chip.h
+++ b/wifi/1.1/default/wifi_chip.h
@@ -20,7 +20,7 @@
 #include <map>
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiChip.h>
+#include <android/hardware/wifi/1.1/IWifiChip.h>
 
 #include "hidl_callback_util.h"
 #include "wifi_ap_iface.h"
@@ -34,15 +34,16 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
+using namespace android::hardware::wifi::V1_0;
 
 /**
  * HIDL interface object used to control a Wifi HAL chip instance.
  * Since there is only a single chip instance used today, there is no
  * identifying handle information stored here.
  */
-class WifiChip : public IWifiChip {
+class WifiChip : public V1_1::IWifiChip {
  public:
   WifiChip(
       ChipId chip_id,
@@ -125,6 +126,9 @@
       getDebugHostWakeReasonStats_cb hidl_status_cb) override;
   Return<void> enableDebugErrorAlerts(
       bool enable, enableDebugErrorAlerts_cb hidl_status_cb) override;
+  Return<void> setTxPowerLimit(
+      int32_t powerInDbm, setTxPowerLimit_cb hidl_status_cb) override;
+  Return<void> resetTxPowerLimit(resetTxPowerLimit_cb hidl_status_cb) override;
 
  private:
   void invalidateAndRemoveAllIfaces();
@@ -176,6 +180,8 @@
   std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
   getDebugHostWakeReasonStatsInternal();
   WifiStatus enableDebugErrorAlertsInternal(bool enable);
+  WifiStatus setTxPowerLimitInternal(int32_t powerInDbm);
+  WifiStatus resetTxPowerLimitInternal();
 
   WifiStatus handleChipConfiguration(ChipModeId mode_id);
   WifiStatus registerDebugRingBufferCallback();
@@ -201,7 +207,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_feature_flags.h b/wifi/1.1/default/wifi_feature_flags.h
similarity index 96%
rename from wifi/1.0/default/wifi_feature_flags.h
rename to wifi/1.1/default/wifi_feature_flags.h
index 3502fbd..5939ffb 100644
--- a/wifi/1.0/default/wifi_feature_flags.h
+++ b/wifi/1.1/default/wifi_feature_flags.h
@@ -20,7 +20,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
 class WifiFeatureFlags {
@@ -33,7 +33,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_legacy_hal.cpp b/wifi/1.1/default/wifi_legacy_hal.cpp
similarity index 98%
rename from wifi/1.0/default/wifi_legacy_hal.cpp
rename to wifi/1.1/default/wifi_legacy_hal.cpp
index b6a7550..c1e1cd3 100644
--- a/wifi/1.0/default/wifi_legacy_hal.cpp
+++ b/wifi/1.1/default/wifi_legacy_hal.cpp
@@ -47,7 +47,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace legacy_hal {
 // Legacy HAL functions accept "C" style function pointers, so use global
@@ -1197,11 +1197,19 @@
       id, wlan_interface_handle_, &msg_internal);
 }
 
+typedef struct {
+    u8 num_ndp_instances;
+    NanDataPathId ndp_instance_id;
+} NanDataPathEndSingleNdpIdRequest;
+
 wifi_error WifiLegacyHal::nanDataEnd(transaction_id id,
-                                     const NanDataPathEndRequest& msg) {
-  NanDataPathEndRequest msg_internal(msg);
-  return global_func_table_.wifi_nan_data_end(
-      id, wlan_interface_handle_, &msg_internal);
+                                     uint32_t ndpInstanceId) {
+  NanDataPathEndSingleNdpIdRequest msg;
+  msg.num_ndp_instances = 1;
+  msg.ndp_instance_id = ndpInstanceId;
+  wifi_error status = global_func_table_.wifi_nan_data_end(
+      id, wlan_interface_handle_, (NanDataPathEndRequest*)&msg);
+  return status;
 }
 
 wifi_error WifiLegacyHal::setCountryCode(std::array<int8_t, 2> code) {
@@ -1308,7 +1316,7 @@
 
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_legacy_hal.h b/wifi/1.1/default/wifi_legacy_hal.h
similarity index 98%
rename from wifi/1.0/default/wifi_legacy_hal.h
rename to wifi/1.1/default/wifi_legacy_hal.h
index 1656f68..fef7999 100644
--- a/wifi/1.0/default/wifi_legacy_hal.h
+++ b/wifi/1.1/default/wifi_legacy_hal.h
@@ -26,7 +26,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 // This is in a separate namespace to prevent typename conflicts between
 // the legacy HAL types and the HIDL interface types.
@@ -268,7 +268,7 @@
                                      const NanDataPathInitiatorRequest& msg);
   wifi_error nanDataIndicationResponse(
       transaction_id id, const NanDataPathIndicationResponse& msg);
-  wifi_error nanDataEnd(transaction_id id, const NanDataPathEndRequest& msg);
+  wifi_error nanDataEnd(transaction_id id, uint32_t ndpInstanceId);
   // AP functions.
   wifi_error setCountryCode(std::array<int8_t, 2> code);
 
@@ -298,7 +298,7 @@
 
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_legacy_hal_stubs.cpp b/wifi/1.1/default/wifi_legacy_hal_stubs.cpp
similarity index 99%
rename from wifi/1.0/default/wifi_legacy_hal_stubs.cpp
rename to wifi/1.1/default/wifi_legacy_hal_stubs.cpp
index 2973430..a5a5d48 100644
--- a/wifi/1.0/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.1/default/wifi_legacy_hal_stubs.cpp
@@ -20,7 +20,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace legacy_hal {
 template <typename>
@@ -136,7 +136,7 @@
 }
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_legacy_hal_stubs.h b/wifi/1.1/default/wifi_legacy_hal_stubs.h
similarity index 96%
rename from wifi/1.0/default/wifi_legacy_hal_stubs.h
rename to wifi/1.1/default/wifi_legacy_hal_stubs.h
index 1cb5f9d..bfc4c9b 100644
--- a/wifi/1.0/default/wifi_legacy_hal_stubs.h
+++ b/wifi/1.1/default/wifi_legacy_hal_stubs.h
@@ -20,7 +20,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace legacy_hal {
 #include <hardware_legacy/wifi_hal.h>
@@ -28,7 +28,7 @@
 bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_mode_controller.cpp b/wifi/1.1/default/wifi_mode_controller.cpp
similarity index 98%
rename from wifi/1.0/default/wifi_mode_controller.cpp
rename to wifi/1.1/default/wifi_mode_controller.cpp
index 7e82d4c..b8a44c2 100644
--- a/wifi/1.0/default/wifi_mode_controller.cpp
+++ b/wifi/1.1/default/wifi_mode_controller.cpp
@@ -48,7 +48,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace mode_controller {
 
@@ -80,7 +80,7 @@
 }
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_mode_controller.h b/wifi/1.1/default/wifi_mode_controller.h
similarity index 95%
rename from wifi/1.0/default/wifi_mode_controller.h
rename to wifi/1.1/default/wifi_mode_controller.h
index a4147a9..6984509 100644
--- a/wifi/1.0/default/wifi_mode_controller.h
+++ b/wifi/1.1/default/wifi_mode_controller.h
@@ -24,9 +24,11 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace mode_controller {
+using namespace android::hardware::wifi::V1_0;
+
 /**
  * Class that encapsulates all firmware mode configuration.
  * This class will perform the necessary firmware reloads to put the chip in the
@@ -51,7 +53,7 @@
 
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_nan_iface.cpp b/wifi/1.1/default/wifi_nan_iface.cpp
similarity index 98%
rename from wifi/1.0/default/wifi_nan_iface.cpp
rename to wifi/1.1/default/wifi_nan_iface.cpp
index 88fb5b2..a111d06 100644
--- a/wifi/1.0/default/wifi_nan_iface.cpp
+++ b/wifi/1.1/default/wifi_nan_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -757,19 +757,13 @@
 }
 WifiStatus WifiNanIface::terminateDataPathRequestInternal(
     uint16_t cmd_id, uint32_t ndpInstanceId) {
-  legacy_hal::NanDataPathEndRequest* legacy_msg = (legacy_hal::NanDataPathEndRequest*)malloc(
-      sizeof(legacy_hal::NanDataPathEndRequest) + sizeof(uint32_t));
-  legacy_msg->num_ndp_instances = 1;
-  legacy_msg->ndp_instance_id[0] = ndpInstanceId;
-
   legacy_hal::wifi_error legacy_status =
-      legacy_hal_.lock()->nanDataEnd(cmd_id, *legacy_msg);
-  free(legacy_msg);
+      legacy_hal_.lock()->nanDataEnd(cmd_id, ndpInstanceId);
   return createWifiStatusFromLegacyError(legacy_status);
 }
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_nan_iface.h b/wifi/1.1/default/wifi_nan_iface.h
similarity index 97%
rename from wifi/1.0/default/wifi_nan_iface.h
rename to wifi/1.1/default/wifi_nan_iface.h
index e1edd29..260d8ab 100644
--- a/wifi/1.0/default/wifi_nan_iface.h
+++ b/wifi/1.1/default/wifi_nan_iface.h
@@ -27,13 +27,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
+using namespace android::hardware::wifi::V1_0;
 
 /**
  * HIDL interface object used to control a NAN Iface instance.
  */
-class WifiNanIface : public IWifiNanIface {
+class WifiNanIface : public V1_0::IWifiNanIface {
  public:
   WifiNanIface(const std::string& ifname,
                const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -132,7 +133,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_p2p_iface.cpp b/wifi/1.1/default/wifi_p2p_iface.cpp
similarity index 97%
rename from wifi/1.0/default/wifi_p2p_iface.cpp
rename to wifi/1.1/default/wifi_p2p_iface.cpp
index 0d055f1..78e08db 100644
--- a/wifi/1.0/default/wifi_p2p_iface.cpp
+++ b/wifi/1.1/default/wifi_p2p_iface.cpp
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -64,7 +64,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_p2p_iface.h b/wifi/1.1/default/wifi_p2p_iface.h
similarity index 92%
rename from wifi/1.0/default/wifi_p2p_iface.h
rename to wifi/1.1/default/wifi_p2p_iface.h
index d2982db..f563a3d 100644
--- a/wifi/1.0/default/wifi_p2p_iface.h
+++ b/wifi/1.1/default/wifi_p2p_iface.h
@@ -25,13 +25,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
+using namespace android::hardware::wifi::V1_0;
 
 /**
  * HIDL interface object used to control a P2P Iface instance.
  */
-class WifiP2pIface : public IWifiP2pIface {
+class WifiP2pIface : public V1_0::IWifiP2pIface {
  public:
   WifiP2pIface(const std::string& ifname,
                const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -56,7 +57,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_rtt_controller.cpp b/wifi/1.1/default/wifi_rtt_controller.cpp
similarity index 99%
rename from wifi/1.0/default/wifi_rtt_controller.cpp
rename to wifi/1.1/default/wifi_rtt_controller.cpp
index f18feae..9ef702d 100644
--- a/wifi/1.0/default/wifi_rtt_controller.cpp
+++ b/wifi/1.1/default/wifi_rtt_controller.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -291,7 +291,7 @@
   return createWifiStatusFromLegacyError(legacy_status);
 }
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_rtt_controller.h b/wifi/1.1/default/wifi_rtt_controller.h
similarity index 97%
rename from wifi/1.0/default/wifi_rtt_controller.h
rename to wifi/1.1/default/wifi_rtt_controller.h
index 7c0abca..5437885 100644
--- a/wifi/1.0/default/wifi_rtt_controller.h
+++ b/wifi/1.1/default/wifi_rtt_controller.h
@@ -27,13 +27,13 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
 /**
  * HIDL interface object used to control all RTT operations.
  */
-class WifiRttController : public IWifiRttController {
+class WifiRttController : public V1_0::IWifiRttController {
  public:
   WifiRttController(const sp<IWifiIface>& bound_iface,
                     const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -97,7 +97,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_sta_iface.cpp b/wifi/1.1/default/wifi_sta_iface.cpp
similarity index 99%
rename from wifi/1.0/default/wifi_sta_iface.cpp
rename to wifi/1.1/default/wifi_sta_iface.cpp
index 3c52048..28f3f02 100644
--- a/wifi/1.0/default/wifi_sta_iface.cpp
+++ b/wifi/1.1/default/wifi_sta_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -623,7 +623,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_sta_iface.h b/wifi/1.1/default/wifi_sta_iface.h
similarity index 97%
rename from wifi/1.0/default/wifi_sta_iface.h
rename to wifi/1.1/default/wifi_sta_iface.h
index 08faa2f..587a5de 100644
--- a/wifi/1.0/default/wifi_sta_iface.h
+++ b/wifi/1.1/default/wifi_sta_iface.h
@@ -27,13 +27,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
+using namespace android::hardware::wifi::V1_0;
 
 /**
  * HIDL interface object used to control a STA Iface instance.
  */
-class WifiStaIface : public IWifiStaIface {
+class WifiStaIface : public V1_0::IWifiStaIface {
  public:
   WifiStaIface(const std::string& ifname,
                const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -159,7 +160,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_status_util.cpp b/wifi/1.1/default/wifi_status_util.cpp
similarity index 98%
rename from wifi/1.0/default/wifi_status_util.cpp
rename to wifi/1.1/default/wifi_status_util.cpp
index c2d0758..3a85e09 100644
--- a/wifi/1.0/default/wifi_status_util.cpp
+++ b/wifi/1.1/default/wifi_status_util.cpp
@@ -19,7 +19,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 
 std::string legacyErrorToString(legacy_hal::wifi_error error) {
@@ -100,7 +100,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.0/default/wifi_status_util.h b/wifi/1.1/default/wifi_status_util.h
similarity index 94%
rename from wifi/1.0/default/wifi_status_util.h
rename to wifi/1.1/default/wifi_status_util.h
index 7f557e0..cc93d66 100644
--- a/wifi/1.0/default/wifi_status_util.h
+++ b/wifi/1.1/default/wifi_status_util.h
@@ -24,8 +24,9 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
+using namespace android::hardware::wifi::V1_0;
 
 std::string legacyErrorToString(legacy_hal::wifi_error error);
 WifiStatus createWifiStatus(WifiStatusCode code,
@@ -36,7 +37,7 @@
 WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
 
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..6b0baf7
--- /dev/null
+++ b/wifi/1.1/vts/functional/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalWifiV1_1TargetTest",
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "VtsHalWifiV1_1TargetTest.cpp",
+        "wifi_chip_hidl_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libcutils",
+        "libhidlbase",
+        "libhidltransport",
+        "libnativehelper",
+        "libutils",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+    ],
+    static_libs: ["VtsHalWifiV1_0TargetTestUtil", "VtsHalHidlTargetTestBase"],
+    cflags: [
+        "-O0",
+        "-g",
+    ],
+}
diff --git a/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
new file mode 100644
index 0000000..160fcd2
--- /dev/null
+++ b/wifi/1.1/vts/functional/VtsHalWifiV1_1TargetTest.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "wifi_hidl_test_utils.h"
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(new WifiHidlEnvironment);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
new file mode 100644
index 0000000..839b6c4
--- /dev/null
+++ b/wifi/1.1/vts/functional/wifi_chip_hidl_test.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include <android/hardware/wifi/1.1/IWifi.h>
+#include <android/hardware/wifi/1.1/IWifiChip.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include "wifi_hidl_call_util.h"
+#include "wifi_hidl_test_utils.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::wifi::V1_0::IfaceType;
+using ::android::hardware::wifi::V1_0::ChipId;
+using ::android::hardware::wifi::V1_0::ChipModeId;
+using ::android::hardware::wifi::V1_0::WifiStatus;
+using ::android::hardware::wifi::V1_0::WifiStatusCode;
+using ::android::hardware::wifi::V1_1::IWifi;
+using ::android::hardware::wifi::V1_1::IWifiChip;
+using ::android::hardware::wifi::V1_0::IWifiStaIface;
+
+namespace {
+constexpr int32_t kFakePowerInDbm = -56;
+}; //namespace
+
+/**
+ * Fixture to use for all Wifi chip HIDL interface tests.
+ */
+class WifiChipHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        wifi_chip_ = IWifiChip::castFrom(getWifiChip());
+        ASSERT_NE(nullptr, wifi_chip_.get());
+    }
+
+    virtual void TearDown() override { stopWifi(); }
+
+   protected:
+    uint32_t configureChipForStaIfaceAndGetCapabilities() {
+        ChipModeId mode_id;
+        EXPECT_TRUE(configureChipToSupportIfaceType(
+            wifi_chip_, IfaceType::STA, &mode_id));
+        const auto& status_and_caps = HIDL_INVOKE(wifi_chip_, getCapabilities);
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status_and_caps.first.code);
+        return status_and_caps.second;
+    }
+
+    sp<IWifiChip> wifi_chip_;
+};
+
+/*
+ * SetTxPowerLimit
+ */
+TEST_F(WifiChipHidlTest, SetTxPowerLimit) {
+    uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
+    const auto& status =
+        HIDL_INVOKE(wifi_chip_, setTxPowerLimit, kFakePowerInDbm);
+    if (caps & IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT) {
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+    } else {
+        EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
+    }
+}
+
+/*
+ * SetTxPowerLimit
+ */
+TEST_F(WifiChipHidlTest, ResetTxPowerLimit) {
+    uint32_t caps = configureChipForStaIfaceAndGetCapabilities();
+    const auto& status =
+        HIDL_INVOKE(wifi_chip_, resetTxPowerLimit);
+    if (caps & IWifiChip::ChipCapabilityMask::SET_TX_POWER_LIMIT) {
+        EXPECT_EQ(WifiStatusCode::SUCCESS, status.code);
+    } else {
+        EXPECT_EQ(WifiStatusCode::ERROR_NOT_SUPPORTED, status.code);
+    }
+}
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 523014f..b4ab98f 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -2,6 +2,8 @@
 subdirs = [
     "1.0",
     "1.0/vts/functional",
+    "1.1",
+    "1.1/vts/functional",
     "offload/1.0",
     "offload/1.0/vts/functional",
     "supplicant/1.0",