Merge "Migrate CAN bus HAL to nested namespaces"
diff --git a/audio/6.0/config/api/current.txt b/audio/6.0/config/api/current.txt
index ddd4d1c..0407d69 100644
--- a/audio/6.0/config/api/current.txt
+++ b/audio/6.0/config/api/current.txt
@@ -361,6 +361,7 @@
     method public String getRawName();
     enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ACCESSIBILITY;
     enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ALARM;
+    enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ASSISTANT;
     enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_BLUETOOTH_SCO;
     enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_DTMF;
     enum_constant public static final audio.policy.configuration.V6_0.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
diff --git a/audio/6.0/config/audio_policy_configuration.xsd b/audio/6.0/config/audio_policy_configuration.xsd
index 3fab7dc..05c8ab4 100644
--- a/audio/6.0/config/audio_policy_configuration.xsd
+++ b/audio/6.0/config/audio_policy_configuration.xsd
@@ -551,6 +551,7 @@
             <xs:enumeration value="AUDIO_STREAM_DTMF"/>
             <xs:enumeration value="AUDIO_STREAM_TTS"/>
             <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+            <xs:enumeration value="AUDIO_STREAM_ASSISTANT"/>
             <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
             <xs:enumeration value="AUDIO_STREAM_PATCH"/>
         </xs:restriction>
diff --git a/audio/common/6.0/types.hal b/audio/common/6.0/types.hal
index e69d969..563e05d 100644
--- a/audio/common/6.0/types.hal
+++ b/audio/common/6.0/types.hal
@@ -106,6 +106,7 @@
     TTS              = 9,  // Transmitted Through Speaker.  Plays over speaker
                            // only, silent on other devices
     ACCESSIBILITY    = 10, // For accessibility talk back prompts
+    ASSISTANT        = 11, // For virtual assistant service
 };
 
 @export(name="audio_source_t", value_prefix="AUDIO_SOURCE_")
diff --git a/audio/effect/6.0/xml/api/current.txt b/audio/effect/6.0/xml/api/current.txt
index 2021639..2dfcb9b 100644
--- a/audio/effect/6.0/xml/api/current.txt
+++ b/audio/effect/6.0/xml/api/current.txt
@@ -82,6 +82,7 @@
   public enum StreamOutputType {
     method public String getRawName();
     enum_constant public static final audio.effects.V6_0.StreamOutputType alarm;
+    enum_constant public static final audio.effects.V6_0.StreamOutputType assistant;
     enum_constant public static final audio.effects.V6_0.StreamOutputType bluetooth_sco;
     enum_constant public static final audio.effects.V6_0.StreamOutputType dtmf;
     enum_constant public static final audio.effects.V6_0.StreamOutputType enforced_audible;
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
deleted file mode 120000
index 9d85fa7..0000000
--- a/audio/effect/6.0/xml/audio_effects_conf.xsd
+++ /dev/null
@@ -1 +0,0 @@
-../../2.0/xml/audio_effects_conf.xsd
\ No newline at end of file
diff --git a/audio/effect/6.0/xml/audio_effects_conf.xsd b/audio/effect/6.0/xml/audio_effects_conf.xsd
new file mode 100644
index 0000000..a7ff20b
--- /dev/null
+++ b/audio/effect/6.0/xml/audio_effects_conf.xsd
@@ -0,0 +1,230 @@
+<?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:enumeration value="voice_performance"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="streamOutputType">
+    <xs:restriction base="xs:string">
+      <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:enumeration value="assistant"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <xs:simpleType name="relativePathType">
+    <xs:restriction base="xs:string">
+      <xs:pattern value="[^/].*"/>
+    </xs:restriction>
+  </xs:simpleType>
+  <!-- Complex types -->
+  <xs:complexType name="librariesType">
+    <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 path of the library .so file
+        relative to the standard effect folders: /(vendor|odm|system)/lib(64)?/soundfx/
+        Example for a library in "/vendor/lib/soundfx/lib.so":
+        <library name="name" path="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="aec:relativePathType" 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="effectType">
+    <xs:complexContent>
+      <xs:extension base="aec:effectImplType">
+        <xs:attribute name="name" type="xs:string" use="required"/>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="effectProxyType">
+    <xs:complexContent>
+      <xs:extension base="aec:effectType">
+        <xs:sequence>
+          <xs:element name="libsw" type="aec:effectImplType"/>
+          <xs:element name="libhw" type="aec:effectImplType"/>
+        </xs:sequence>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
+  <xs:complexType name="effectsType">
+    <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"/>
+        <effectProxy name="proxied" library="proxy" uuid="xxxx">
+            <libsw library="sw_bundle" uuid="yyyy"/>
+            <libhw library="offload_bundle" uuid="zzzz"/>
+        </effectProxy>
+      </xs:documentation>
+    </xs:annotation>
+    <xs:choice maxOccurs="unbounded">
+      <xs:element name="effect" type="aec:effectType" minOccurs="0" maxOccurs="unbounded"/>
+      <xs:element name="effectProxy" type="aec:effectProxyType" minOccurs="0" maxOccurs="unbounded"/>
+    </xs:choice>
+  </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:librariesType"/>
+        <xs:element name="effects" type="aec:effectsType"/>
+        <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|aec:effects/aec:effectProxy"/>
+      <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>
\ No newline at end of file
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index f9c25d1..2050038 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -62,6 +62,7 @@
         "impl/vhal_v2_0/EmulatedVehicleHal.cpp",
         "impl/vhal_v2_0/VehicleEmulator.cpp",
         "impl/vhal_v2_0/PipeComm.cpp",
+        "impl/vhal_v2_0/ProtoMessageConverter.cpp",
         "impl/vhal_v2_0/SocketComm.cpp",
         "impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
         "impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
@@ -98,6 +99,21 @@
     test_suites: ["general-tests"],
 }
 
+cc_test {
+    name: "android.hardware.automotive.vehicle@2.0-default-impl-unit-tests",
+    vendor: true,
+    defaults: ["vhal_v2_0_defaults"],
+    srcs: [
+        "impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp",
+    ],
+    static_libs: [
+        "android.hardware.automotive.vehicle@2.0-default-impl-lib",
+        "android.hardware.automotive.vehicle@2.0-libproto-native",
+        "libprotobuf-cpp-lite",
+    ],
+    test_suites: ["general-tests"],
+}
+
 cc_binary {
     name: "android.hardware.automotive.vehicle@2.0-service",
     defaults: ["vhal_v2_0_defaults"],
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
index bf1de81..136b2e0 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
@@ -41,7 +41,7 @@
     }
 }
 
-void CommConn::sendMessage(emulator::EmulatorMessage const& msg) {
+void CommConn::sendMessage(vhal_proto::EmulatorMessage const& msg) {
     int numBytes = msg.ByteSize();
     std::vector<uint8_t> buffer(static_cast<size_t>(numBytes));
     if (!msg.SerializeToArray(buffer.data(), numBytes)) {
@@ -61,9 +61,9 @@
             break;
         }
 
-        emulator::EmulatorMessage rxMsg;
+        vhal_proto::EmulatorMessage rxMsg;
         if (rxMsg.ParseFromArray(buffer.data(), static_cast<int32_t>(buffer.size()))) {
-            emulator::EmulatorMessage respMsg;
+            vhal_proto::EmulatorMessage respMsg;
             mMessageProcessor->processMessage(rxMsg, respMsg);
 
             sendMessage(respMsg);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
index 87b0dfc..6d36da4 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
@@ -44,8 +44,8 @@
      * Process a single message received over a CommConn. Populate the given respMsg with the reply
      * message we should send.
      */
-    virtual void processMessage(emulator::EmulatorMessage const& rxMsg,
-                                emulator::EmulatorMessage& respMsg) = 0;
+    virtual void processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+                                vhal_proto::EmulatorMessage& respMsg) = 0;
 };
 
 /**
@@ -93,7 +93,7 @@
     /**
      * Serialized and send the given message to the other side.
      */
-    void sendMessage(emulator::EmulatorMessage const& msg);
+    void sendMessage(vhal_proto::EmulatorMessage const& msg);
 
    protected:
     std::unique_ptr<std::thread> mReadThread;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp
new file mode 100644
index 0000000..77cb114
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.cpp
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ProtoMsgConverter"
+
+#include <memory>
+#include <vector>
+
+#include <log/log.h>
+
+#include <vhal_v2_0/VehicleUtils.h>
+
+#include "ProtoMessageConverter.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+namespace proto_msg_converter {
+
+// If protobuf class PROTO_VALUE has value in field PROTO_VARNAME,
+// then casting the value by CAST and copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME
+#define CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \
+                                                  VHAL_TYPE_VARNAME, CAST)                     \
+    if (PROTO_VALUE.has_##PROTO_VARNAME()) {                                                   \
+        (VHAL_TYPE_VALUE)->VHAL_TYPE_VARNAME = CAST(PROTO_VALUE.PROTO_VARNAME());              \
+    }
+
+// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to
+// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME, every element of PROTO_VECNAME
+// is casted by CAST
+#define CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \
+                                            VHAL_TYPE_VECNAME, CAST)                     \
+    do {                                                                                 \
+        (VHAL_TYPE_VALUE)->VHAL_TYPE_VECNAME.resize(PROTO_VALUE.PROTO_VECNAME##_size()); \
+        size_t idx = 0;                                                                  \
+        for (auto& value : PROTO_VALUE.PROTO_VECNAME()) {                                \
+            VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME[idx++] = CAST(value);                     \
+        }                                                                                \
+    } while (0)
+
+// If protobuf message has value in field PROTO_VARNAME,
+// then copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME
+#define CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \
+                                             VHAL_TYPE_VARNAME)                           \
+    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(                                            \
+            PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VARNAME, /*NO CAST*/)
+
+// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to
+// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME
+#define COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \
+                                       VHAL_TYPE_VECNAME)                           \
+    CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(                                            \
+            PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VECNAME, /*NO CAST*/)
+
+void toProto(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) {
+    protoCfg->set_prop(cfg.prop);
+    protoCfg->set_access(toInt(cfg.access));
+    protoCfg->set_change_mode(toInt(cfg.changeMode));
+    protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
+
+    for (auto& configElement : cfg.configArray) {
+        protoCfg->add_config_array(configElement);
+    }
+
+    if (cfg.configString.size() > 0) {
+        protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
+    }
+
+    protoCfg->clear_area_configs();
+    for (auto& areaConfig : cfg.areaConfigs) {
+        auto* protoACfg = protoCfg->add_area_configs();
+        protoACfg->set_area_id(areaConfig.areaId);
+
+        switch (getPropType(cfg.prop)) {
+            case VehiclePropertyType::STRING:
+            case VehiclePropertyType::BOOLEAN:
+            case VehiclePropertyType::INT32_VEC:
+            case VehiclePropertyType::INT64_VEC:
+            case VehiclePropertyType::FLOAT_VEC:
+            case VehiclePropertyType::BYTES:
+            case VehiclePropertyType::MIXED:
+                // Do nothing.  These types don't have min/max values
+                break;
+            case VehiclePropertyType::INT64:
+                protoACfg->set_min_int64_value(areaConfig.minInt64Value);
+                protoACfg->set_max_int64_value(areaConfig.maxInt64Value);
+                break;
+            case VehiclePropertyType::FLOAT:
+                protoACfg->set_min_float_value(areaConfig.minFloatValue);
+                protoACfg->set_max_float_value(areaConfig.maxFloatValue);
+                break;
+            case VehiclePropertyType::INT32:
+                protoACfg->set_min_int32_value(areaConfig.minInt32Value);
+                protoACfg->set_max_int32_value(areaConfig.maxInt32Value);
+                break;
+            default:
+                ALOGW("%s: Unknown property type:  0x%x", __func__, toInt(getPropType(cfg.prop)));
+                break;
+        }
+    }
+
+    protoCfg->set_min_sample_rate(cfg.minSampleRate);
+    protoCfg->set_max_sample_rate(cfg.maxSampleRate);
+}
+
+void fromProto(VehiclePropConfig* cfg, const vhal_proto::VehiclePropConfig& protoCfg) {
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, prop, cfg, prop);
+    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, access, cfg, access,
+                                              static_cast<VehiclePropertyAccess>);
+    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, change_mode, cfg, changeMode,
+                                              static_cast<VehiclePropertyChangeMode>);
+    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, config_array, cfg, configArray);
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, config_string, cfg, configString);
+
+    auto cast_to_acfg = [](const vhal_proto::VehicleAreaConfig& protoAcfg) {
+        VehicleAreaConfig acfg;
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, area_id, &acfg, areaId);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int32_value, &acfg, minInt32Value);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int32_value, &acfg, maxInt32Value);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int64_value, &acfg, minInt64Value);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int64_value, &acfg, maxInt64Value);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_float_value, &acfg, minFloatValue);
+        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_float_value, &acfg, maxFloatValue);
+        return acfg;
+    };
+
+    CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, area_configs, cfg, areaConfigs, cast_to_acfg);
+
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, min_sample_rate, cfg, minSampleRate);
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, max_sample_rate, cfg, maxSampleRate);
+}
+
+void toProto(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue& val) {
+    protoVal->set_prop(val.prop);
+    protoVal->set_value_type(toInt(getPropType(val.prop)));
+    protoVal->set_timestamp(val.timestamp);
+    protoVal->set_status((vhal_proto::VehiclePropStatus)(val.status));
+    protoVal->set_area_id(val.areaId);
+
+    // Copy value data if it is set.
+    //  - for bytes and strings, this is indicated by size > 0
+    //  - for int32, int64, and float, copy the values if vectors have data
+    if (val.value.stringValue.size() > 0) {
+        protoVal->set_string_value(val.value.stringValue.c_str(), val.value.stringValue.size());
+    }
+
+    if (val.value.bytes.size() > 0) {
+        protoVal->set_bytes_value(val.value.bytes.data(), val.value.bytes.size());
+    }
+
+    for (auto& int32Value : val.value.int32Values) {
+        protoVal->add_int32_values(int32Value);
+    }
+
+    for (auto& int64Value : val.value.int64Values) {
+        protoVal->add_int64_values(int64Value);
+    }
+
+    for (auto& floatValue : val.value.floatValues) {
+        protoVal->add_float_values(floatValue);
+    }
+}
+
+void fromProto(VehiclePropValue* val, const vhal_proto::VehiclePropValue& protoVal) {
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, prop, val, prop);
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, timestamp, val, timestamp);
+    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, status, val, status,
+                                              static_cast<VehiclePropertyStatus>);
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, area_id, val, areaId);
+
+    // Copy value data
+    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, string_value, val, value.stringValue);
+
+    auto cast_proto_bytes_to_vec = [](auto&& bytes) {
+        return std::vector<uint8_t>(bytes.begin(), bytes.end());
+    };
+    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, bytes_value, val, value.bytes,
+                                              cast_proto_bytes_to_vec);
+
+    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int32_values, val, value.int32Values);
+    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int64_values, val, value.int64Values);
+    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, float_values, val, value.floatValues);
+}
+
+#undef COPY_PROTOBUF_VEC_TO_VHAL_TYPE
+#undef CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE
+#undef CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE
+#undef CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE
+
+}  // namespace proto_msg_converter
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h
new file mode 100644
index 0000000..01f3beb
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/ProtoMessageConverter.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_ProtoMessageConverter_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_ProtoMessageConverter_H_
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+#include "VehicleHalProto.pb.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+namespace proto_msg_converter {
+
+// VehiclePropConfig
+
+void toProto(vhal_proto::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg);
+
+void fromProto(VehiclePropConfig* cfg, const vhal_proto::VehiclePropConfig& protoCfg);
+
+// VehiclePropValue
+
+void toProto(vhal_proto::VehiclePropValue* protoVal, const VehiclePropValue& val);
+
+void fromProto(VehiclePropValue* val, const vhal_proto::VehiclePropValue& protoVal);
+
+}  // namespace proto_msg_converter
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
index 068333c..916c320 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
@@ -60,7 +60,7 @@
     }
 }
 
-void SocketComm::sendMessage(emulator::EmulatorMessage const& msg) {
+void SocketComm::sendMessage(vhal_proto::EmulatorMessage const& msg) {
     std::lock_guard<std::mutex> lock(mMutex);
     for (std::unique_ptr<SocketConn> const& conn : mOpenConnections) {
         conn->sendMessage(msg);
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
index 88b852b..52326b9 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.h
@@ -47,7 +47,7 @@
     /**
      * Serialized and send the given message to all connected clients.
      */
-    void sendMessage(emulator::EmulatorMessage const& msg);
+    void sendMessage(vhal_proto::EmulatorMessage const& msg);
 
    private:
     int mListenFd;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
index 9dc7085..263ca62 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.cpp
@@ -24,6 +24,7 @@
 #include <vhal_v2_0/VehicleUtils.h>
 
 #include "PipeComm.h"
+#include "ProtoMessageConverter.h"
 #include "SocketComm.h"
 
 #include "VehicleEmulator.h"
@@ -62,11 +63,11 @@
  * changed.
  */
 void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) {
-    emulator::EmulatorMessage msg;
-    emulator::VehiclePropValue *val = msg.add_value();
+    vhal_proto::EmulatorMessage msg;
+    vhal_proto::VehiclePropValue* val = msg.add_value();
     populateProtoVehiclePropValue(val, &propValue);
-    msg.set_status(emulator::RESULT_OK);
-    msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
+    msg.set_status(vhal_proto::RESULT_OK);
+    msg.set_msg_type(vhal_proto::SET_PROPERTY_ASYNC);
 
     mSocketComm->sendMessage(msg);
     if (mPipeComm) {
@@ -77,17 +78,17 @@
 void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage const& rxMsg,
                                   VehicleEmulator::EmulatorMessage& respMsg) {
     std::vector<VehiclePropConfig> configs = mHal->listProperties();
-    emulator::VehiclePropGet getProp = rxMsg.prop(0);
+    vhal_proto::VehiclePropGet getProp = rxMsg.prop(0);
 
-    respMsg.set_msg_type(emulator::GET_CONFIG_RESP);
-    respMsg.set_status(emulator::ERROR_INVALID_PROPERTY);
+    respMsg.set_msg_type(vhal_proto::GET_CONFIG_RESP);
+    respMsg.set_status(vhal_proto::ERROR_INVALID_PROPERTY);
 
     for (auto& config : configs) {
         // Find the config we are looking for
         if (config.prop == getProp.prop()) {
-            emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+            vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config();
             populateProtoVehicleConfig(protoCfg, config);
-            respMsg.set_status(emulator::RESULT_OK);
+            respMsg.set_status(vhal_proto::RESULT_OK);
             break;
         }
     }
@@ -97,11 +98,11 @@
                                      VehicleEmulator::EmulatorMessage& respMsg) {
     std::vector<VehiclePropConfig> configs = mHal->listProperties();
 
-    respMsg.set_msg_type(emulator::GET_CONFIG_ALL_RESP);
-    respMsg.set_status(emulator::RESULT_OK);
+    respMsg.set_msg_type(vhal_proto::GET_CONFIG_ALL_RESP);
+    respMsg.set_status(vhal_proto::RESULT_OK);
 
     for (auto& config : configs) {
-        emulator::VehiclePropConfig* protoCfg = respMsg.add_config();
+        vhal_proto::VehiclePropConfig* protoCfg = respMsg.add_config();
         populateProtoVehicleConfig(protoCfg, config);
     }
 }
@@ -109,11 +110,11 @@
 void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
                                     VehicleEmulator::EmulatorMessage& respMsg) {
     int32_t areaId = 0;
-    emulator::VehiclePropGet getProp = rxMsg.prop(0);
+    vhal_proto::VehiclePropGet getProp = rxMsg.prop(0);
     int32_t propId = getProp.prop();
-    emulator::Status status = emulator::ERROR_INVALID_PROPERTY;
+    vhal_proto::Status status = vhal_proto::ERROR_INVALID_PROPERTY;
 
-    respMsg.set_msg_type(emulator::GET_PROPERTY_RESP);
+    respMsg.set_msg_type(vhal_proto::GET_PROPERTY_RESP);
 
     if (getProp.has_area_id()) {
         areaId = getProp.area_id();
@@ -127,9 +128,9 @@
         StatusCode halStatus;
         auto val = mHal->get(request, &halStatus);
         if (val != nullptr) {
-            emulator::VehiclePropValue* protoVal = respMsg.add_value();
+            vhal_proto::VehiclePropValue* protoVal = respMsg.add_value();
             populateProtoVehiclePropValue(protoVal, val.get());
-            status = emulator::RESULT_OK;
+            status = vhal_proto::RESULT_OK;
         }
     }
 
@@ -138,12 +139,12 @@
 
 void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage const& /* rxMsg */,
                                        VehicleEmulator::EmulatorMessage& respMsg) {
-    respMsg.set_msg_type(emulator::GET_PROPERTY_ALL_RESP);
-    respMsg.set_status(emulator::RESULT_OK);
+    respMsg.set_msg_type(vhal_proto::GET_PROPERTY_ALL_RESP);
+    respMsg.set_status(vhal_proto::RESULT_OK);
 
     {
         for (const auto& prop : mHal->getAllProperties()) {
-            emulator::VehiclePropValue* protoVal = respMsg.add_value();
+            vhal_proto::VehiclePropValue* protoVal = respMsg.add_value();
             populateProtoVehiclePropValue(protoVal, &prop);
         }
     }
@@ -151,7 +152,7 @@
 
 void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
                                     VehicleEmulator::EmulatorMessage& respMsg) {
-    emulator::VehiclePropValue protoVal = rxMsg.value(0);
+    vhal_proto::VehiclePropValue protoVal = rxMsg.value(0);
     VehiclePropValue val = {
             .timestamp = elapsedRealtimeNano(),
             .areaId = protoVal.area_id(),
@@ -159,7 +160,7 @@
             .status = (VehiclePropertyStatus)protoVal.status(),
     };
 
-    respMsg.set_msg_type(emulator::SET_PROPERTY_RESP);
+    respMsg.set_msg_type(vhal_proto::SET_PROPERTY_RESP);
 
     // Copy value data if it is set.  This automatically handles complex data types if needed.
     if (protoVal.has_string_value()) {
@@ -187,120 +188,42 @@
     }
 
     bool halRes = mHal->setPropertyFromVehicle(val);
-    respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY);
+    respMsg.set_status(halRes ? vhal_proto::RESULT_OK : vhal_proto::ERROR_INVALID_PROPERTY);
 }
 
-void VehicleEmulator::processMessage(emulator::EmulatorMessage const& rxMsg,
-                                     emulator::EmulatorMessage& respMsg) {
+void VehicleEmulator::processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+                                     vhal_proto::EmulatorMessage& respMsg) {
     switch (rxMsg.msg_type()) {
-        case emulator::GET_CONFIG_CMD:
+        case vhal_proto::GET_CONFIG_CMD:
             doGetConfig(rxMsg, respMsg);
             break;
-        case emulator::GET_CONFIG_ALL_CMD:
+        case vhal_proto::GET_CONFIG_ALL_CMD:
             doGetConfigAll(rxMsg, respMsg);
             break;
-        case emulator::GET_PROPERTY_CMD:
+        case vhal_proto::GET_PROPERTY_CMD:
             doGetProperty(rxMsg, respMsg);
             break;
-        case emulator::GET_PROPERTY_ALL_CMD:
+        case vhal_proto::GET_PROPERTY_ALL_CMD:
             doGetPropertyAll(rxMsg, respMsg);
             break;
-        case emulator::SET_PROPERTY_CMD:
+        case vhal_proto::SET_PROPERTY_CMD:
             doSetProperty(rxMsg, respMsg);
             break;
         default:
             ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
-            respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
+            respMsg.set_status(vhal_proto::ERROR_UNIMPLEMENTED_CMD);
             break;
     }
 }
 
-void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+void VehicleEmulator::populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg,
                                                  const VehiclePropConfig& cfg) {
-    protoCfg->set_prop(cfg.prop);
-    protoCfg->set_access(toInt(cfg.access));
-    protoCfg->set_change_mode(toInt(cfg.changeMode));
-    protoCfg->set_value_type(toInt(getPropType(cfg.prop)));
-
-    for (auto& configElement : cfg.configArray) {
-        protoCfg->add_config_array(configElement);
-    }
-
-    if (cfg.configString.size() > 0) {
-        protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
-    }
-
-    // Populate the min/max values based on property type
-    switch (getPropType(cfg.prop)) {
-        case VehiclePropertyType::STRING:
-        case VehiclePropertyType::BOOLEAN:
-        case VehiclePropertyType::INT32_VEC:
-        case VehiclePropertyType::INT64_VEC:
-        case VehiclePropertyType::FLOAT_VEC:
-        case VehiclePropertyType::BYTES:
-        case VehiclePropertyType::MIXED:
-            // Do nothing.  These types don't have min/max values
-            break;
-        case VehiclePropertyType::INT64:
-            if (cfg.areaConfigs.size() > 0) {
-                emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
-                aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
-                aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
-            }
-            break;
-        case VehiclePropertyType::FLOAT:
-            if (cfg.areaConfigs.size() > 0) {
-                emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
-                aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
-                aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
-            }
-            break;
-        case VehiclePropertyType::INT32:
-            if (cfg.areaConfigs.size() > 0) {
-                emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
-                aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
-                aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
-            }
-            break;
-        default:
-            ALOGW("%s: Unknown property type:  0x%x", __func__, toInt(getPropType(cfg.prop)));
-            break;
-    }
-
-    protoCfg->set_min_sample_rate(cfg.minSampleRate);
-    protoCfg->set_max_sample_rate(cfg.maxSampleRate);
+    return proto_msg_converter::toProto(protoCfg, cfg);
 }
 
-void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+void VehicleEmulator::populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal,
                                                     const VehiclePropValue* val) {
-    protoVal->set_prop(val->prop);
-    protoVal->set_value_type(toInt(getPropType(val->prop)));
-    protoVal->set_timestamp(val->timestamp);
-    protoVal->set_status((emulator::VehiclePropStatus)(val->status));
-    protoVal->set_area_id(val->areaId);
-
-    // Copy value data if it is set.
-    //  - for bytes and strings, this is indicated by size > 0
-    //  - for int32, int64, and float, copy the values if vectors have data
-    if (val->value.stringValue.size() > 0) {
-        protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
-    }
-
-    if (val->value.bytes.size() > 0) {
-        protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
-    }
-
-    for (auto& int32Value : val->value.int32Values) {
-        protoVal->add_int32_values(int32Value);
-    }
-
-    for (auto& int64Value : val->value.int64Values) {
-        protoVal->add_int64_values(int64Value);
-    }
-
-    for (auto& floatValue : val->value.floatValues) {
-        protoVal->add_float_values(floatValue);
-    }
+    return proto_msg_converter::toProto(protoVal, *val);
 }
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
index 58e387a..82947be 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleEmulator.h
@@ -72,21 +72,21 @@
     virtual ~VehicleEmulator();
 
     void doSetValueFromClient(const VehiclePropValue& propValue);
-    void processMessage(emulator::EmulatorMessage const& rxMsg,
-                        emulator::EmulatorMessage& respMsg) override;
+    void processMessage(vhal_proto::EmulatorMessage const& rxMsg,
+                        vhal_proto::EmulatorMessage& respMsg) override;
 
    private:
     friend class ConnectionThread;
-    using EmulatorMessage = emulator::EmulatorMessage;
+    using EmulatorMessage = vhal_proto::EmulatorMessage;
 
     void doGetConfig(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
     void doGetConfigAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
     void doGetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
     void doGetPropertyAll(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
     void doSetProperty(EmulatorMessage const& rxMsg, EmulatorMessage& respMsg);
-    void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
+    void populateProtoVehicleConfig(vhal_proto::VehiclePropConfig* protoCfg,
                                     const VehiclePropConfig& cfg);
-    void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
+    void populateProtoVehiclePropValue(vhal_proto::VehiclePropValue* protoVal,
                                        const VehiclePropValue* val);
 
 private:
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
index 04df5a8..4902a5d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleHalProto.proto
@@ -16,7 +16,7 @@
 
 syntax = "proto2";
 
-package emulator;
+package vhal_proto;
 
 // CMD messages are from workstation --> VHAL
 // RESP messages are from VHAL --> workstation
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
index 7ce3c32..2cc6595 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/proto/VehicleServer.proto
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-syntax = "proto2";
+syntax = "proto3";
 
-package emulator;
+package vhal_proto;
 
 import "google/protobuf/empty.proto";
 import "VehicleHalProto.proto";
@@ -32,7 +32,7 @@
 }
 
 message VehicleHalCallStatus {
-    required VehicleHalStatusCode status_code      = 1;
+    VehicleHalStatusCode status_code    = 1;
 }
 
 service VehicleServer {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp
new file mode 100644
index 0000000..3817e44
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <utils/SystemClock.h>
+
+#include "vhal_v2_0/DefaultConfig.h"
+#include "vhal_v2_0/ProtoMessageConverter.h"
+#include "vhal_v2_0/VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace impl {
+namespace proto_msg_converter {
+
+namespace {
+
+void CheckPropConfigConversion(const VehiclePropConfig& config) {
+    vhal_proto::VehiclePropConfig protoCfg;
+    VehiclePropConfig tmpConfig;
+
+    toProto(&protoCfg, config);
+    fromProto(&tmpConfig, protoCfg);
+
+    EXPECT_EQ(config.prop, tmpConfig.prop);
+    EXPECT_EQ(config.access, tmpConfig.access);
+    EXPECT_EQ(config.changeMode, tmpConfig.changeMode);
+    EXPECT_EQ(config.configString, tmpConfig.configString);
+    EXPECT_EQ(config.minSampleRate, tmpConfig.minSampleRate);
+    EXPECT_EQ(config.maxSampleRate, tmpConfig.maxSampleRate);
+    EXPECT_EQ(config.configArray, tmpConfig.configArray);
+
+    EXPECT_EQ(config.areaConfigs.size(), tmpConfig.areaConfigs.size());
+
+    auto cfgType = getPropType(config.prop);
+    for (size_t idx = 0; idx < std::min(config.areaConfigs.size(), tmpConfig.areaConfigs.size());
+         ++idx) {
+        auto& lhs = config.areaConfigs[idx];
+        auto& rhs = tmpConfig.areaConfigs[idx];
+        EXPECT_EQ(lhs.areaId, rhs.areaId);
+        switch (cfgType) {
+            case VehiclePropertyType::INT64:
+                EXPECT_EQ(lhs.minInt64Value, rhs.minInt64Value);
+                EXPECT_EQ(lhs.maxInt64Value, rhs.maxInt64Value);
+                break;
+            case VehiclePropertyType::FLOAT:
+                EXPECT_EQ(lhs.minFloatValue, rhs.minFloatValue);
+                EXPECT_EQ(lhs.maxFloatValue, rhs.maxFloatValue);
+                break;
+            case VehiclePropertyType::INT32:
+                EXPECT_EQ(lhs.minInt32Value, rhs.minInt32Value);
+                EXPECT_EQ(lhs.maxInt32Value, rhs.maxInt32Value);
+                break;
+            default:
+                // ignore min/max values
+                break;
+        }
+    }
+}
+
+void CheckPropValueConversion(const VehiclePropValue& val) {
+    vhal_proto::VehiclePropValue protoVal;
+    VehiclePropValue tmpVal;
+
+    toProto(&protoVal, val);
+    fromProto(&tmpVal, protoVal);
+
+    EXPECT_EQ(val, tmpVal);
+}
+
+TEST(ProtoMessageConverterTest, basic) {
+    for (auto& property : impl::kVehicleProperties) {
+        CheckPropConfigConversion(property.config);
+
+        VehiclePropValue prop;
+        prop.timestamp = elapsedRealtimeNano();
+        prop.areaId = 123;
+        prop.prop = property.config.prop;
+        prop.value = property.initialValue;
+        prop.status = VehiclePropertyStatus::ERROR;
+        CheckPropValueConversion(prop);
+    }
+}
+
+}  // namespace
+
+}  // namespace proto_msg_converter
+}  // namespace impl
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.6/Android.bp b/camera/device/3.6/Android.bp
new file mode 100644
index 0000000..8766b93
--- /dev/null
+++ b/camera/device/3.6/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.device@3.6",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ICameraDeviceSession.hal",
+        "ICameraOfflineSession.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.common@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.camera.device@3.5",
+        "android.hardware.graphics.common@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
diff --git a/camera/device/3.6/ICameraDeviceSession.hal b/camera/device/3.6/ICameraDeviceSession.hal
new file mode 100644
index 0000000..00ebcc3
--- /dev/null
+++ b/camera/device/3.6/ICameraDeviceSession.hal
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.6;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.5::ICameraDeviceSession;
+import @3.5::StreamConfiguration;
+import ICameraOfflineSession;
+
+/**
+ * Camera device active session interface.
+ *
+ * Obtained via ICameraDevice::open(), this interface contains the methods to
+ * configure and request captures from an active camera device.
+ */
+interface ICameraDeviceSession extends @3.5::ICameraDeviceSession {
+    /**
+     * configureStreams_3_6:
+     *
+     * Identical to @3.5::ICameraDeviceSession.configureStreams, except that:
+     *
+     * - a boolean supportOffline is added to HalStreamConfiguration to indicate
+     *   if this stream can be switched to offline mode later.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On successful stream configuration.
+     *     INTERNAL_ERROR:
+     *         If there has been a fatal error and the device is no longer
+     *         operational. Only close() can be called successfully by the
+     *         framework after this error is returned.
+     *     ILLEGAL_ARGUMENT:
+     *         If the requested stream configuration is invalid. Some examples
+     *         of invalid stream configurations include:
+     *           - Including more than 1 INPUT stream
+     *           - Not including any OUTPUT streams
+     *           - Including streams with unsupported formats, or an unsupported
+     *             size for that format.
+     *           - Including too many output streams of a certain format.
+     *           - Unsupported rotation configuration
+     *           - Stream sizes/formats don't satisfy the
+     *             StreamConfigurationMode requirements
+     *             for non-NORMAL mode, or the requested operation_mode is not
+     *             supported by the HAL.
+     *           - Unsupported usage flag
+     *         The camera service cannot filter out all possible illegal stream
+     *         configurations, since some devices may support more simultaneous
+     *         streams or larger stream resolutions than the minimum required
+     *         for a given camera device hardware level. The HAL must return an
+     *         ILLEGAL_ARGUMENT for any unsupported stream set, and then be
+     *         ready to accept a future valid stream configuration in a later
+     *         configureStreams call.
+     * @return halConfiguration The stream parameters desired by the HAL for
+     *     each stream, including maximum buffers, the usage flags, and the
+     *     override format.
+     */
+    configureStreams_3_6(@3.5::StreamConfiguration requestedConfiguration)
+        generates (Status status, HalStreamConfiguration halConfiguration);
+
+    /**
+     * switchToOffline:
+     *
+     * Switch the current running session from actively streaming mode to the
+     * offline mode. See ICameraOfflineSession for more details.
+     *
+     * The streamsToKeep argument contains list of streams IDs where application
+     * still needs its output. For all streams application does not need anymore,
+     * camera HAL can send ERROR_BUFFER to speed up the transition, or even send
+     * ERROR_REQUEST if all output targets of a request is not needed. By the
+     * time this call returns, camera HAL must have returned all buffers coming
+     * from streams no longer needed and have erased buffer caches of such streams.
+     *
+     * For all requests that are going to be transferred to offline session,
+     * the ICameraDeviceSession is responsible to capture all input buffers from
+     * the image sensor before the switchToOffline call returns. Before
+     * switchToOffline returns, camera HAL must have completed all requests not
+     * switching to offline mode, and collected information on what streams and
+     * requests are going to continue in the offline session, in the
+     * offlineSessionInfo output argument.
+     *
+     * If there are no requests qualified to be transferred to offline session,
+     * the camera HAL must return a null ICameraOfflineSession object with OK
+     * status. In this scenario, the camera HAL still must flush all inflight
+     * requests and unconfigure all streams before returning this call.
+     *
+     * After switchToOffline returns, the ICameraDeviceSession must be back to
+     * unconfigured state as if it is just created and no streams are configured.
+     * Also, camera HAL must not call any methods in ICameraDeviceCallback since
+     * all unfinished requests are now transferred to the offline session.
+     * After the call returns, camera service may then call close to close
+     * the camera device, or call configureStream* again to reconfigure the
+     * camera and then send new capture requests with processCaptureRequest. In
+     * the latter case, it is legitimate for camera HAL to call methods in
+     * ICameraDeviceCallback again in response to the newly submitted capture
+     * requests.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On switching to offline session and unconfiguring streams
+     *         successfully.
+     *     ILLEGAL_ARGUMENT:
+     *         If camera does not support offline mode in any one of streams
+     *         in streamsToKeep argument. Note that the camera HAL must report
+     *         if a stream supports offline mode in HalStreamConfiguration
+     *         output of configureStreams_3_6 method. If all streams in
+     *         streamsToKeep argument support offline mode, then the camera HAL
+     *         must not return this error.
+     *
+     *
+     * @return offlineSessionInfo Information on what streams and requests will
+     *     be transferred to offline session to continue processing.
+     *
+     * @return offlineSession The offline session object camera service will use
+     *     to interact with.
+     */
+    switchToOffline(vec<int32_t> streamsToKeep) generates (Status status,
+        CameraOfflineSessionInfo offlineSessionInfo, ICameraOfflineSession offlineSession);
+};
diff --git a/camera/device/3.6/ICameraOfflineSession.hal b/camera/device/3.6/ICameraOfflineSession.hal
new file mode 100644
index 0000000..03cea64
--- /dev/null
+++ b/camera/device/3.6/ICameraOfflineSession.hal
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.6;
+
+import @3.5::ICameraDeviceCallback;
+
+/**
+ * Camera device offline session interface.
+ *
+ * Obtained via ICameraDeviceSession::switchToOffline(), this interface contains
+ * the methods and callback interfaces that define how camera service interacts
+ * with an offline session.
+ *
+ * An offline session contains some unfinished capture requests that were submitted
+ * to the parent ICameraDeviceSession before calling switchToOffline, and is
+ * responsible for delivering these capture results back to camera service regardless
+ * of whether the parent camera device is still opened or not. An offline session must
+ * not have access to the camera device's image sensor. During switchToOffline
+ * call, camera HAL must capture all necessary frames from the image sensor that
+ * is needed for completing the requests offline later.
+ */
+interface ICameraOfflineSession {
+    /**
+     * Set the callbacks for offline session to communicate with camera service.
+     *
+     * Offline session is responsible to store all callbacks the camera HAL
+     * generated after the return of ICameraDeviceSession::switchToOffline, and
+     * send them to camera service once this method is called.
+     *
+     * Camera service must not call this method more than once, so these
+     * callbacks can be assumed to be constant after the first setCallback call.
+     */
+    setCallback(ICameraDeviceCallback cb);
+
+    /**
+     * getCaptureResultMetadataQueue:
+     *
+     * Retrieves the queue used along with
+     * ICameraDeviceCallback#processCaptureResult.
+     *
+     * Clients to ICameraOfflineSession must:
+     * - Call getCaptureRequestMetadataQueue to retrieve the fast message queue;
+     * - In implementation of ICameraDeviceCallback, test whether
+     *   .fmqResultSize field is zero.
+     *     - If .fmqResultSize != 0, read result metadata from the fast message
+     *       queue;
+     *     - otherwise, read result metadata in CaptureResult.result.
+     *
+     * @return queue the queue that implementation writes result metadata to.
+     */
+    getCaptureResultMetadataQueue() generates (fmq_sync<uint8_t> queue);
+
+    /**
+     * Close the offline session and release all resources.
+     *
+     * Camera service may call this method before or after the offline session
+     * has finished all requests it needs to handle. If there are still unfinished
+     * requests when close is called, camera HAL must send ERROR_REQUEST for
+     * all unfinished requests and return all buffers via
+     * ICameraDeviceCallback#processCaptureResult or
+     * ICameraDeviceCallback#returnStreamBuffers.
+     * Also, all buffer caches maintained by the offline session must be erased
+     * before the close call returns.
+     */
+    close();
+};
diff --git a/camera/device/3.6/types.hal b/camera/device/3.6/types.hal
new file mode 100644
index 0000000..743b139
--- /dev/null
+++ b/camera/device/3.6/types.hal
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.6;
+
+import @3.2::BufferCache;
+import @3.4::HalStream;
+
+/**
+ * OfflineRequest:
+ *
+ * Information about a capture request being switched to offline mode via the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct OfflineRequest {
+    /**
+     * Must match a inflight CaptureRequest sent by camera service
+     */
+    uint32_t frameNumber;
+
+    /**
+     * Stream IDs for outputs that will be returned via ICameraDeviceCallback.
+     * The stream ID must be within one of offline stream listed in
+     * CameraOfflineSessionInfo.
+     * Camera service will validate these pending buffers are matching camera
+     * service's record to make sure no buffers are leaked during the
+     * switchToOffline call.
+     */
+    vec<int32_t> pendingStreams;
+};
+
+/**
+ * OfflineStream:
+ *
+ * Information about a stream being switched to offline mode via the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct OfflineStream {
+    /**
+     * IDs of a stream to be transferred to offline session.
+     *
+     * For devices that do not support HAL buffer management, this must be
+     * one of stream ID listed in streamsToKeep argument of the
+     * switchToOffline call.
+     * For devices that support HAL buffer management, this could be any stream
+     * that was configured right before calling switchToOffline.
+     */
+    int32_t id;
+
+    /**
+     * Number of outstanding buffers that will be returned via offline session
+     */
+    uint32_t numOutstandingBuffers;
+
+    /**
+     * Buffer ID of buffers currently cached between camera service and this
+     * stream, which may or may not be owned by the camera HAL right now.
+     * See StreamBuffer#bufferId for more details.
+     */
+    vec<uint64_t> circulatingBufferIds;
+};
+
+/**
+ * CameraOfflineSessionInfo:
+ *
+ * Information about pending outputs that's being transferred to an offline
+ * session from an active session using the
+ * ICameraDeviceSession#switchToOffline method.
+ *
+ */
+struct CameraOfflineSessionInfo {
+    /**
+     * Information on what streams will be preserved in offline session.
+     * Streams not listed here will be removed by camera service after
+     * switchToOffline call returns.
+     */
+    vec<OfflineStream> offlineStreams;
+
+    /**
+     * Information for requests that will be handled by offline session
+     * Camera service will validate this matches what camera service has on
+     * record.
+     */
+    vec<OfflineRequest> offlineRequests;
+};
+
+/**
+ * HalStream:
+ *
+ * The camera HAL's response to each requested stream configuration.
+ *
+ * This version extends the @3.4 HalStream with the physicalCameraId
+ * field
+ */
+struct HalStream {
+    /**
+     * The definition of HalStream from the prior version.
+     */
+    @3.4::HalStream v3_4;
+
+    /**
+     * Whether this stream can be switch to offline mode.
+     *
+     * For devices that does not support the OFFLINE_PROCESSING capability, this
+     * fields will always be false.
+     *
+     * For devices support the OFFLINE_PROCESSING capability: any input stream
+     * and any output stream that can be output of the input stream must set
+     * this field to true. Also any stream of YUV420_888 format or JPEG format,
+     * with CPU_READ usage flag, must set this field to true. All other streams
+     * are up to camera HAL to advertise support or not, though it is not
+     * recommended to list support for streams with hardware composer or video
+     * encoder usage flags as these streams tend to be targeted continuously and
+     * can lead to long latency when trying to switch to offline.
+     *
+     */
+    bool supportOffline;
+};
+
+/**
+ * HalStreamConfiguration:
+ *
+ * Identical to @3.4::HalStreamConfiguration, except that it contains @3.6::HalStream entries.
+ *
+ */
+struct HalStreamConfiguration {
+    vec<HalStream> streams;
+};
diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal
index cef0397..f5034cc 100644
--- a/camera/metadata/3.2/types.hal
+++ b/camera/metadata/3.2/types.hal
@@ -410,7 +410,7 @@
      *
      * <p>List of the maximum number of regions that can be used for metering in
      * auto-exposure (AE), auto-white balance (AWB), and auto-focus (AF);
-     * this corresponds to the the maximum number of elements in
+     * this corresponds to the maximum number of elements in
      * ANDROID_CONTROL_AE_REGIONS, ANDROID_CONTROL_AWB_REGIONS,
      * and ANDROID_CONTROL_AF_REGIONS.</p>
      *
diff --git a/camera/metadata/3.5/Android.bp b/camera/metadata/3.5/Android.bp
index 4ebd069..224c369 100644
--- a/camera/metadata/3.5/Android.bp
+++ b/camera/metadata/3.5/Android.bp
@@ -16,4 +16,3 @@
     ],
     gen_java: true,
 }
-
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
index b9451c8..62899ec 100644
--- a/camera/metadata/3.5/types.hal
+++ b/camera/metadata/3.5/types.hal
@@ -35,12 +35,22 @@
  * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
  */
 enum CameraMetadataTag : @3.4::CameraMetadataTag {
-    /** android.control.availableBokehCapabilities [static, int32[], public]
+    /** android.control.availableBokehMaxSizes [static, int32[], ndk_public]
      *
-     * <p>The list of bokeh modes that are supported by this camera device, and each bokeh mode's
-     * maximum streaming (non-stall) size with bokeh effect.</p>
+     * <p>The list of bokeh modes for ANDROID_CONTROL_BOKEH_MODE that are supported by this camera
+     * device, and each bokeh mode's maximum streaming (non-stall) size with bokeh effect.</p>
+     *
+     * @see ANDROID_CONTROL_BOKEH_MODE
      */
-    ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+    ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+
+    /** android.control.availableBokehZoomRatioRanges [static, float[], ndk_public]
+     *
+     * <p>The ranges of supported zoom ratio for non-OFF ANDROID_CONTROL_BOKEH_MODE.</p>
+     *
+     * @see ANDROID_CONTROL_BOKEH_MODE
+     */
+    ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES,
 
     /** android.control.bokehMode [dynamic, enum, public]
      *
@@ -48,6 +58,18 @@
      */
     ANDROID_CONTROL_BOKEH_MODE,
 
+    /** android.control.zoomRatioRange [static, float[], public]
+     *
+     * <p>Minimum and maximum zoom ratios supported by this camera device.</p>
+     */
+    ANDROID_CONTROL_ZOOM_RATIO_RANGE,
+
+    /** android.control.zoomRatio [dynamic, float, public]
+     *
+     * <p>The desired zoom ratio</p>
+     */
+    ANDROID_CONTROL_ZOOM_RATIO,
+
     ANDROID_CONTROL_END_3_5,
 
 };
@@ -71,4 +93,5 @@
 enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
         @3.4::CameraMetadataEnumAndroidRequestAvailableCapabilities {
     ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,
+    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING,
 };
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 69ec0d9..650ec8b 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -20,6 +20,7 @@
 #include <chrono>
 #include <mutex>
 #include <regex>
+#include <string>
 #include <unordered_map>
 #include <unordered_set>
 #include <condition_variable>
@@ -755,6 +756,7 @@
             const hidl_vec<hidl_string>& deviceNames);
     void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
     void verifyBokehCharacteristics(const camera_metadata_t* metadata);
+    void verifyZoomCharacteristics(const camera_metadata_t* metadata);
     void verifyRecommendedConfigs(const CameraMetadata& metadata);
     void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
     void verifyMonochromeCameraResult(
@@ -776,6 +778,8 @@
     void verifySessionReconfigurationQuery(sp<device::V3_5::ICameraDeviceSession> session3_5,
             camera_metadata* oldSessionParams, camera_metadata* newSessionParams);
 
+    void verifyRequestTemplate(const camera_metadata_t* metadata, RequestTemplate requestTemplate);
+
     bool isDepthOnly(camera_metadata_t* staticMeta);
 
     static Status getAvailableOutputStreams(const camera_metadata_t *staticMeta,
@@ -2857,13 +2861,7 @@
                                             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);
+                                    verifyRequestTemplate(metadata, reqTemplate);
                                 } else {
                                     ASSERT_EQ(0u, req.size());
                                 }
@@ -5671,6 +5669,11 @@
         return;
     }
 
+    camera_metadata_ro_entry entry;
+    int retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+    bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+
     std::string version, cameraId;
     ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId));
     std::unordered_set<std::string> physicalIds;
@@ -5678,15 +5681,37 @@
     for (auto physicalId : physicalIds) {
         ASSERT_NE(physicalId, cameraId);
         bool isPublicId = false;
+        std::string fullPublicId;
         for (auto& deviceName : deviceNames) {
             std::string publicVersion, publicId;
             ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
             if (physicalId == publicId) {
                 isPublicId = true;
+                fullPublicId = deviceName;
                 break;
             }
         }
         if (isPublicId) {
+            ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> subDevice;
+            Return<void> ret;
+            ret = mProvider->getCameraDeviceInterface_V3_x(
+                fullPublicId, [&](auto status, const auto& device) {
+                    ASSERT_EQ(Status::OK, status);
+                    ASSERT_NE(device, nullptr);
+                    subDevice = device;
+                });
+            ASSERT_TRUE(ret.isOk());
+
+            ret = subDevice->getCameraCharacteristics(
+                    [&](auto status, const auto& chars) {
+                ASSERT_EQ(Status::OK, status);
+                retcode = find_camera_metadata_ro_entry(
+                        (const camera_metadata_t *)chars.data(),
+                        ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+                bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+                ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
+            });
+            ASSERT_TRUE(ret.isOk());
             continue;
         }
 
@@ -5702,6 +5727,12 @@
                 [&](auto status, const auto& chars) {
             verifyCameraCharacteristics(status, chars);
             verifyMonochromeCharacteristics(chars, deviceVersion);
+
+            retcode = find_camera_metadata_ro_entry(
+                    (const camera_metadata_t *)chars.data(),
+                    ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+            bool subCameraHasZoomRatioRange = (0 == retcode && entry.count == 2);
+            ASSERT_EQ(hasZoomRatioRange, subCameraHasZoomRatioRange);
         });
         ASSERT_TRUE(ret.isOk());
 
@@ -5721,8 +5752,7 @@
     // Make sure ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID is available in
     // result keys.
     if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) {
-        camera_metadata_ro_entry entry;
-        int retcode = find_camera_metadata_ro_entry(metadata,
+        retcode = find_camera_metadata_ro_entry(metadata,
                 ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
         if ((0 == retcode) && (entry.count > 0)) {
                 ASSERT_NE(std::find(entry.data.i32, entry.data.i32 + entry.count,
@@ -5822,6 +5852,7 @@
     }
 
     verifyBokehCharacteristics(metadata);
+    verifyZoomCharacteristics(metadata);
 }
 
 void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadata) {
@@ -5852,38 +5883,51 @@
 
     retcode = find_camera_metadata_ro_entry(metadata,
             ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
-    bool hasBokehCharacteristicsKey = false;
+    bool hasBokehMaxSizesKey = false;
+    bool hasBokehZoomRatioRangesKey = false;
     if ((0 == retcode) && (entry.count > 0)) {
-        hasBokehCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count,
-                ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES) != entry.data.i32+entry.count;
+        hasBokehMaxSizesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES) != entry.data.i32+entry.count;
+        hasBokehZoomRatioRangesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES) != entry.data.i32+entry.count;
     } else {
         ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
     }
+
+    camera_metadata_ro_entry maxSizesEntry;
     retcode = find_camera_metadata_ro_entry(metadata,
-            ANDROID_CONTROL_AVAILABLE_BOKEH_CAPABILITIES, &entry);
-    bool hasAvailableBokehCaps = (0 == retcode && entry.count > 0);
+            ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES, &maxSizesEntry);
+    bool hasBokehMaxSizes = (0 == retcode && maxSizesEntry.count > 0);
+
+    camera_metadata_ro_entry zoomRatioRangesEntry;
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES, &zoomRatioRangesEntry);
+    bool hasBokehZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0);
 
     // Bokeh keys must all be available, or all be unavailable.
-    bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehCharacteristicsKey &&
-            !hasAvailableBokehCaps;
+    bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehMaxSizesKey &&
+            !hasBokehZoomRatioRangesKey && !hasBokehMaxSizes && !hasBokehZoomRatioRanges;
     if (noBokeh) {
         return;
     }
-    bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehCharacteristicsKey &&
-            hasAvailableBokehCaps;
+    bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehMaxSizesKey &&
+            hasBokehZoomRatioRangesKey && hasBokehMaxSizes && hasBokehZoomRatioRanges;
     ASSERT_TRUE(hasBokeh);
 
     // Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS.
-    ASSERT_TRUE(entry.count == 6 || entry.count == 9);
+    // Only valid combinations: {OFF, CONTINUOUS}, {OFF, STILL_CAPTURE}, and
+    // {OFF, CONTINUOUS, STILL_CAPTURE}.
+    ASSERT_TRUE((maxSizesEntry.count == 6 && zoomRatioRangesEntry.count == 2) ||
+            (maxSizesEntry.count == 9 && zoomRatioRangesEntry.count == 4));
     bool hasOffMode = false;
     bool hasStillCaptureMode = false;
     bool hasContinuousMode = false;
     std::vector<AvailableStream> outputStreams;
     ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams));
-    for (int i = 0; i < entry.count; i += 3) {
-        int32_t mode = entry.data.i32[i];
-        int32_t maxWidth = entry.data.i32[i+1];
-        int32_t maxHeight = entry.data.i32[i+2];
+    for (int i = 0, j = 0; i < maxSizesEntry.count && j < zoomRatioRangesEntry.count; i += 3) {
+        int32_t mode = maxSizesEntry.data.i32[i];
+        int32_t maxWidth = maxSizesEntry.data.i32[i+1];
+        int32_t maxHeight = maxSizesEntry.data.i32[i+2];
         switch (mode) {
             case ANDROID_CONTROL_BOKEH_MODE_OFF:
                 hasOffMode = true;
@@ -5891,9 +5935,11 @@
                 break;
             case ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE:
                 hasStillCaptureMode = true;
+                j += 2;
                 break;
             case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS:
                 hasContinuousMode = true;
+                j += 2;
                 break;
             default:
                 ADD_FAILURE() << "Invalid bokehMode advertised: " << mode;
@@ -5901,6 +5947,7 @@
         }
 
         if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) {
+            // Make sure size is supported.
             bool sizeSupported = false;
             for (const auto& stream : outputStreams) {
                 if ((stream.format == static_cast<int32_t>(PixelFormat::YCBCR_420_888) ||
@@ -5911,12 +5958,102 @@
                 }
             }
             ASSERT_TRUE(sizeSupported);
+
+            // Make sure zoom range is valid
+            float minZoomRatio = zoomRatioRangesEntry.data.f[0];
+            float maxZoomRatio = zoomRatioRangesEntry.data.f[1];
+            ASSERT_GT(minZoomRatio, 0.0f);
+            ASSERT_LE(minZoomRatio, maxZoomRatio);
         }
     }
     ASSERT_TRUE(hasOffMode);
     ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode);
 }
 
+void CameraHidlTest::verifyZoomCharacteristics(const camera_metadata_t* metadata) {
+    camera_metadata_ro_entry entry;
+    int retcode = 0;
+
+    // Check key availability in capabilities, request and result.
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &entry);
+    float maxDigitalZoom = 1.0;
+    if ((0 == retcode) && (entry.count == 1)) {
+        maxDigitalZoom = entry.data.f[0];
+    } else {
+        ADD_FAILURE() << "Get camera scalerAvailableMaxDigitalZoom failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
+    bool hasZoomRequestKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasZoomRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32+entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableRequestKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
+    bool hasZoomResultKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasZoomResultKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_ZOOM_RATIO) != entry.data.i32+entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableResultKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
+    bool hasZoomCharacteristicsKey = false;
+    if ((0 == retcode) && (entry.count > 0)) {
+        hasZoomCharacteristicsKey = std::find(entry.data.i32, entry.data.i32+entry.count,
+                ANDROID_CONTROL_ZOOM_RATIO_RANGE) != entry.data.i32+entry.count;
+    } else {
+        ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
+    }
+
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_ZOOM_RATIO_RANGE, &entry);
+    bool hasZoomRatioRange = (0 == retcode && entry.count == 2);
+
+    // Zoom keys must all be available, or all be unavailable.
+    bool noZoomRatio = !hasZoomRequestKey && !hasZoomResultKey && !hasZoomCharacteristicsKey &&
+            !hasZoomRatioRange;
+    if (noZoomRatio) {
+        return;
+    }
+    bool hasZoomRatio = hasZoomRequestKey && hasZoomResultKey && hasZoomCharacteristicsKey &&
+            hasZoomRatioRange;
+    ASSERT_TRUE(hasZoomRatio);
+
+    float minZoomRatio = entry.data.f[0];
+    float maxZoomRatio = entry.data.f[1];
+    if (maxDigitalZoom != maxZoomRatio) {
+        ADD_FAILURE() << "Maximum zoom ratio is different than maximum digital zoom!";
+    }
+    if (minZoomRatio > maxZoomRatio) {
+        ADD_FAILURE() << "Maximum zoom ratio is less than minimum zoom ratio!";
+    }
+    if (minZoomRatio > 1.0f) {
+        ADD_FAILURE() << "Minimum zoom ratio is more than 1.0!";
+    }
+    if (maxZoomRatio < 1.0f) {
+        ADD_FAILURE() << "Maximum zoom ratio is less than 1.0!";
+    }
+
+    // Make sure CROPPING_TYPE is CENTER_ONLY
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_SCALER_CROPPING_TYPE, &entry);
+    if ((0 == retcode) && (entry.count == 1)) {
+        int8_t croppingType = entry.data.u8[0];
+        ASSERT_EQ(croppingType, ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY);
+    } else {
+        ADD_FAILURE() << "Get camera scalerCroppingType failed!";
+    }
+}
+
 void CameraHidlTest::verifyMonochromeCharacteristics(const CameraMetadata& chars,
         int deviceVersion) {
     const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
@@ -6415,6 +6552,26 @@
     }
 }
 
+void CameraHidlTest::verifyRequestTemplate(const camera_metadata_t* metadata,
+        RequestTemplate requestTemplate) {
+    ASSERT_NE(nullptr, metadata);
+    size_t entryCount =
+            get_camera_metadata_entry_count(metadata);
+    ALOGI("template %u metadata entry count is %zu", (int32_t)requestTemplate, entryCount);
+    // 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);
+
+    // Check zoomRatio
+    camera_metadata_ro_entry zoomRatioEntry;
+    int foundZoomRatio = find_camera_metadata_ro_entry(metadata,
+            ANDROID_CONTROL_ZOOM_RATIO, &zoomRatioEntry);
+    if (foundZoomRatio == 0) {
+        ASSERT_EQ(zoomRatioEntry.count, 1);
+        ASSERT_EQ(zoomRatioEntry.data.f[0], 1.0f);
+    }
+}
+
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, CameraHidlTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(ICameraProvider::descriptor)),
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index f5acdd4..1e3f743 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -388,6 +388,13 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.rebootescrow</name>
+        <interface>
+            <name>IRebootEscrow</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.secure_element</name>
         <version>1.0</version>
diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp
index aef0340..9e99c33 100644
--- a/contexthub/1.0/vts/functional/Android.bp
+++ b/contexthub/1.0/vts/functional/Android.bp
@@ -19,6 +19,8 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalContexthubV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.contexthub@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
-
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
index 045cc4e..161b2f0 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -4,5 +4,5 @@
 stange@google.com
 
 #VTS team
-yim@google.com
+dshi@google.com
 trong@google.com
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index 629477a..a1d173b 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -16,13 +16,14 @@
 
 #define LOG_TAG "contexthub_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/contexthub/1.0/IContexthub.h>
 #include <android/hardware/contexthub/1.0/IContexthubCallback.h>
 #include <android/hardware/contexthub/1.0/types.h>
 #include <android/log.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 #include <cinttypes>
@@ -76,69 +77,44 @@
 }
 
 // Gets a list of valid hub IDs in the system
-std::vector<uint32_t> getHubIds() {
-  static std::vector<uint32_t> hubIds;
+std::vector<std::string> getHubIds(const std::string& service_name) {
+    std::vector<std::string> hubIds;
 
-  if (hubIds.size() == 0) {
-    sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>();
+    sp<IContexthub> hubApi = IContexthub::getService(service_name);
 
     if (hubApi != nullptr) {
-      for (const ContextHub& hub : getHubsSync(hubApi)) {
-        hubIds.push_back(hub.hubId);
-      }
+        for (const ContextHub& hub : getHubsSync(hubApi)) {
+            hubIds.push_back(std::to_string(hub.hubId));
+        }
     }
-  }
 
-  ALOGD("Running tests against all %zu reported hubs", hubIds.size());
-  return hubIds;
+    ALOGD("Running tests against all %zu reported hubs for service %s", hubIds.size(),
+          service_name.c_str());
+    return hubIds;
 }
 
-// Test environment for Contexthub HIDL HAL.
-class ContexthubHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static ContexthubHidlEnvironment* Instance() {
-    static ContexthubHidlEnvironment* instance = new ContexthubHidlEnvironment;
-    return instance;
-  }
+// Test fixture parameterized by hub ID, initializes the HAL and makes the context hub API handle
+// available.
+class ContexthubHidlTest : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+  public:
+    virtual void SetUp() override {
+        hubApi = IContexthub::getService(std::get<0>(GetParam()));
+        ASSERT_NE(hubApi, nullptr);
 
-  virtual void registerTestServices() override { registerTestService<IContexthub>(); }
- private:
-  ContexthubHidlEnvironment() {}
-};
+        // getHubs() must be called at least once for proper initialization of the
+        // HAL implementation
+        getHubsSync(hubApi);
+    }
 
-// Base test fixture that initializes the HAL and makes the context hub API
-// handle available
-class ContexthubHidlTestBase : public ::testing::VtsHalHidlTargetTestBase {
- public:
-  virtual void SetUp() override {
-    hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>(
-        ContexthubHidlEnvironment::Instance()->getServiceName<IContexthub>());
-    ASSERT_NE(hubApi, nullptr);
+    uint32_t getHubId() { return std::stoi(std::get<1>(GetParam())); }
 
-    // getHubs() must be called at least once for proper initialization of the
-    // HAL implementation
-    getHubsSync(hubApi);
-  }
+    Result registerCallback(sp<IContexthubCallback> cb) {
+        Result result = hubApi->registerCallback(getHubId(), cb);
+        ALOGD("Registered callback, result %" PRIu32, result);
+        return result;
+    }
 
-  virtual void TearDown() override {}
-
-  sp<IContexthub> hubApi;
-};
-
-// Test fixture parameterized by hub ID
-class ContexthubHidlTest : public ContexthubHidlTestBase,
-                           public ::testing::WithParamInterface<uint32_t> {
- public:
-  uint32_t getHubId() {
-    return GetParam();
-  }
-
-  Result registerCallback(sp<IContexthubCallback> cb) {
-    Result result = hubApi->registerCallback(getHubId(), cb);
-    ALOGD("Registered callback, result %" PRIu32, result);
-    return result;
-  }
+    sp<IContexthub> hubApi;
 };
 
 // Base callback implementation that just logs all callbacks by default
@@ -202,24 +178,24 @@
 }
 
 // Ensures that the metadata reported in getHubs() is sane
-TEST_F(ContexthubHidlTestBase, TestGetHubs) {
-  hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
-  ALOGD("System reports %zu hubs", hubs.size());
+TEST_P(ContexthubHidlTest, TestGetHubs) {
+    hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
+    ALOGD("System reports %zu hubs", hubs.size());
 
-  for (const ContextHub& hub : hubs) {
-    ALOGD("Checking hub ID %" PRIu32, hub.hubId);
+    for (const ContextHub& hub : hubs) {
+        ALOGD("Checking hub ID %" PRIu32, hub.hubId);
 
-    EXPECT_FALSE(hub.name.empty());
-    EXPECT_FALSE(hub.vendor.empty());
-    EXPECT_FALSE(hub.toolchain.empty());
-    EXPECT_GT(hub.peakMips, 0);
-    EXPECT_GE(hub.stoppedPowerDrawMw, 0);
-    EXPECT_GE(hub.sleepPowerDrawMw, 0);
-    EXPECT_GT(hub.peakPowerDrawMw, 0);
+        EXPECT_FALSE(hub.name.empty());
+        EXPECT_FALSE(hub.vendor.empty());
+        EXPECT_FALSE(hub.toolchain.empty());
+        EXPECT_GT(hub.peakMips, 0);
+        EXPECT_GE(hub.stoppedPowerDrawMw, 0);
+        EXPECT_GE(hub.sleepPowerDrawMw, 0);
+        EXPECT_GT(hub.peakPowerDrawMw, 0);
 
-    // Minimum 128 byte MTU as required by CHRE API v1.0
-    EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
-  }
+        // Minimum 128 byte MTU as required by CHRE API v1.0
+        EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
+    }
 }
 
 TEST_P(ContexthubHidlTest, TestRegisterCallback) {
@@ -388,20 +364,28 @@
                                       cb->promise.get_future()));
 }
 
-// Parameterize all SingleContexthubTest tests against each valid hub ID
-INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubHidlTest,
-                        ::testing::ValuesIn(getHubIds()));
-INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubTxnTest,
-                        ::testing::ValuesIn(getHubIds()));
+// Return the test parameters of a vecter of tuples for all IContexthub services and each of its hub
+// id: <service name of IContexthub, hub id of the IContexthub service>
+static std::vector<std::tuple<std::string, std::string>> get_parameters() {
+    std::vector<std::tuple<std::string, std::string>> parameters;
+    std::vector<std::string> service_names =
+            android::hardware::getAllHalInstanceNames(IContexthub::descriptor);
+    for (const std::string& service_name : service_names) {
+        std::vector<std::string> ids = getHubIds(service_name);
+        for (const std::string& id : ids) {
+            parameters.push_back(std::make_tuple(service_name, id));
+        }
+    }
 
-} // anonymous namespace
-
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(ContexthubHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  ContexthubHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI ("Test result = %d", status);
-  return status;
+    return parameters;
 }
 
+static std::vector<std::tuple<std::string, std::string>> kTestParameters = get_parameters();
+
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubTxnTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
+}  // anonymous namespace
diff --git a/current.txt b/current.txt
index 1fe17d5..c6e206d 100644
--- a/current.txt
+++ b/current.txt
@@ -585,6 +585,7 @@
 f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardware.automotive.evs@1.0::IEvsEnumerator
 d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types
 2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
+cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
 b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
 eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
 f1109cbb10297b7429a11fab42afa912710b303c9bf20bd5cdb8bd57b9c84186 android.hardware.neuralnetworks@1.0::types
@@ -605,7 +606,7 @@
 2df5d5866b37776f25079c0e54b54350a2abe4e025a59c9e02a7d3abe8ca00e8 android.hardware.audio@6.0::IStreamIn
 78e4138cc8307c11fc777c3bd376e581ba4ba48196b05ca1d7cdfa515c87b48a android.hardware.audio@6.0::IStreamOut
 997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback
-1349686814402fa10f711cc5763bc629aafc64a5f5843b4b21b8cd86ffb923e6 android.hardware.audio.common@6.0::types
+8c4232772efeb9905b4c287723e0ee8b2c4bf5ba11728d051171b070e3d79144 android.hardware.audio.common@6.0::types
 817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
 525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect
 8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect
@@ -649,17 +650,17 @@
 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
 cf1d55e8c68300090747ab90b94c22e4c859b29c84ced68a317c595bb115eab2 android.hardware.neuralnetworks@1.3::types
 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
-03d37dfebbc27b13adce1ed6389ac483bf7cf32488ca14037c5569bc3e903e4f android.hardware.wifi.hostapd@1.2::IHostapd
+36b3acf78ac4ecf8156be8741c1d8332cdce7a1ebf4dfa1562952f14a94e6c87 android.hardware.wifi.hostapd@1.2::IHostapd
 2defa258951e25a132aaeb36e3febe6f41bf9c6dbb1b1ebdf0b41708ab4e107e android.hardware.wifi.hostapd@1.2::types
 a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
-44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
+213457930af81ff3ea344fbc9d4a0d0a2bb70527f96b7b6a32ee3b5e4c17057e android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
 619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
-c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
+a6163000e2804472924733bcf8b4269db776460cc4df64f9c4dc8350d7aeafc5 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
 9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types
-0e3c23f1c815469fdcdc39bc33a486817771c7c6b6e5303f2f25569499fc6c69 android.hardware.radio@1.5::types
-52abfa4c94104189fa4b2bc3132fc7c9852b7428283463b020d1a3671a4f374c android.hardware.radio@1.5::IRadio
+7a4ba60b5ddedf497e5d2bdff7d72b7d4a811969000e28677dd9e2389e683b34 android.hardware.radio@1.5::types
+afa2d6cf4c0ba4b8482d5bcc097594ad5bc49be0bf3003034f75955cdaf66045 android.hardware.radio@1.5::IRadio
 3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication
-957ffbaf195aa046431ebe05a5906d215e80650e8e4933b394d6454b217ef3a9 android.hardware.radio@1.5::IRadioResponse
+f4888f9676890b43a459c6380f335fea7a6ad32ed3bafafeb018a88d6c0be8a4 android.hardware.radio@1.5::IRadioResponse
 55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types
 b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
 742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 24de37d..88fbff8 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -172,7 +172,14 @@
                 hasGnssHalVersion_2_0 = registered.size() != 0;
             });
 
-    return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
+    bool hasGnssHalVersion_2_1 = false;
+    manager->listManifestByInterface(
+            "android.hardware.gnss@2.1::IGnss",
+            [&hasGnssHalVersion_2_1](const hidl_vec<hidl_string>& registered) {
+                hasGnssHalVersion_2_1 = registered.size() != 0;
+            });
+
+    return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0 && !hasGnssHalVersion_2_1;
 }
 
 GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation(
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index 8ca3f68..b3a3203 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -16,11 +16,14 @@
 
 #define LOG_TAG "GnssHalTest"
 
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <gnss_hal_test.h>
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
 #include <chrono>
 #include "Utils.h"
 
-#include <gtest/gtest.h>
+using ::android::hardware::hidl_string;
 
 using ::android::hardware::gnss::common::Utils;
 
@@ -99,7 +102,6 @@
 
     EXPECT_TRUE(result.isOk());
     EXPECT_TRUE(result);
-
     /*
      * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
      * so allow time to demodulate ephemeris over the air.
@@ -148,6 +150,27 @@
     }
 }
 
+bool GnssHalTest::IsGnssHalVersion_2_0() const {
+    using ::android::hidl::manager::V1_2::IServiceManager;
+    sp<IServiceManager> manager = ::android::hardware::defaultServiceManager1_2();
+
+    bool hasGnssHalVersion_2_0 = false;
+    manager->listManifestByInterface(
+            "android.hardware.gnss@2.0::IGnss",
+            [&hasGnssHalVersion_2_0](const hidl_vec<hidl_string>& registered) {
+                hasGnssHalVersion_2_0 = registered.size() != 0;
+            });
+
+    bool hasGnssHalVersion_2_1 = false;
+    manager->listManifestByInterface(
+            "android.hardware.gnss@2.1::IGnss",
+            [&hasGnssHalVersion_2_1](const hidl_vec<hidl_string>& registered) {
+                hasGnssHalVersion_2_1 = registered.size() != 0;
+            });
+
+    return hasGnssHalVersion_2_0 && !hasGnssHalVersion_2_1;
+}
+
 GnssHalTest::GnssCallback::GnssCallback()
     : info_cbq_("system_info"),
       name_cbq_("name"),
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 4f7b87a..55dc1bc 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -181,6 +181,12 @@
     void StopAndClearLocations();
 
     /*
+     * IsGnssHalVersion_2_0:
+     * returns  true if the GNSS HAL version is exactly 2.0.
+     */
+    bool IsGnssHalVersion_2_0() const;
+
+    /*
      * SetPositionMode:
      * Helper function to set positioning mode and verify output
      */
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index c442cc6..0fa08b9 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -182,6 +182,10 @@
  * 3. state is valid.
  */
 TEST_P(GnssHalTest, TestGnssMeasurementFields) {
+    if (!IsGnssHalVersion_2_0()) {
+        ALOGI("Test GnssMeasurementFields skipped. GNSS HAL version is greater than 2.0.");
+        return;
+    }
     const int kFirstGnssMeasurementTimeoutSeconds = 10;
 
     auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_2_0();
@@ -464,7 +468,7 @@
         }
         EXPECT_LE(location_called_count, i);
         if (location_called_count != i) {
-            ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
+            ALOGW("GetLocationLowPower test - too many locations received. %d vs. %d expected ",
                   location_called_count, i);
         }
 
@@ -601,6 +605,11 @@
  * formerly strongest satellite
  */
 TEST_P(GnssHalTest, BlacklistIndividualSatellites) {
+    if (!IsGnssHalVersion_2_0()) {
+        ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 2.0.");
+        return;
+    }
+
     if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
         ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
               " not supported.");
@@ -746,6 +755,11 @@
  * 4a & b) Clean up by turning off location, and send in empty blacklist.
  */
 TEST_P(GnssHalTest, BlacklistConstellation) {
+    if (!IsGnssHalVersion_2_0()) {
+        ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0.");
+        return;
+    }
+
     if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
         ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
         return;
diff --git a/gnss/2.1/default/Android.bp b/gnss/2.1/default/Android.bp
index 57233aa..7ef9990 100644
--- a/gnss/2.1/default/Android.bp
+++ b/gnss/2.1/default/Android.bp
@@ -23,8 +23,9 @@
     srcs: [
         "Gnss.cpp",
         "GnssMeasurement.cpp",
+        "GnssMeasurementCorrections.cpp",
         "GnssConfiguration.cpp",
-        "service.cpp"
+        "service.cpp",
     ],
     shared_libs: [
         "libhidlbase",
diff --git a/gnss/2.1/default/Gnss.cpp b/gnss/2.1/default/Gnss.cpp
index fd7a9df..6b61a82 100644
--- a/gnss/2.1/default/Gnss.cpp
+++ b/gnss/2.1/default/Gnss.cpp
@@ -18,11 +18,14 @@
 
 #include "Gnss.h"
 #include "GnssMeasurement.h"
+#include "GnssMeasurementCorrections.h"
 #include "Utils.h"
 
 #include <log/log.h>
 
 using ::android::hardware::gnss::common::Utils;
+using ::android::hardware::gnss::measurement_corrections::V1_0::implementation::
+        GnssMeasurementCorrections;
 
 namespace android {
 namespace hardware {
@@ -87,7 +90,8 @@
 }
 
 Return<void> Gnss::cleanup() {
-    // TODO implement
+    sGnssCallback_2_1 = nullptr;
+    sGnssCallback_2_0 = nullptr;
     return Void();
 }
 
@@ -170,8 +174,9 @@
 }
 
 Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode,
-                                       V1_0::IGnss::GnssPositionRecurrence, uint32_t, uint32_t,
-                                       uint32_t, bool) {
+                                       V1_0::IGnss::GnssPositionRecurrence, uint32_t minIntervalMs,
+                                       uint32_t, uint32_t, bool) {
+    mMinIntervalMs = minIntervalMs;
     return true;
 }
 
@@ -215,7 +220,7 @@
         ALOGE("%s: Unable to invoke callback", __func__);
     }
 
-    auto gnssName = "Google Mock GNSS Implementation v2.0";
+    auto gnssName = "Google Mock GNSS Implementation v2.1";
     ret = sGnssCallback_2_0->gnssNameCb(gnssName);
     if (!ret.isOk()) {
         ALOGE("%s: Unable to invoke callback", __func__);
@@ -251,8 +256,8 @@
 
 Return<sp<measurement_corrections::V1_0::IMeasurementCorrections>>
 Gnss::getExtensionMeasurementCorrections() {
-    // TODO implement
-    return ::android::sp<measurement_corrections::V1_0::IMeasurementCorrections>{};
+    ALOGD("Gnss::getExtensionMeasurementCorrections()");
+    return new GnssMeasurementCorrections();
 }
 
 Return<sp<visibility_control::V1_0::IGnssVisibilityControl>> Gnss::getExtensionVisibilityControl() {
@@ -266,7 +271,7 @@
 }
 
 Return<bool> Gnss::injectBestLocation_2_0(const V2_0::GnssLocation&) {
-    // TODO implement
+    // TODO(b/124012850): Implement function.
     return bool{};
 }
 
@@ -316,6 +321,7 @@
 
 void Gnss::reportSvStatus(const hidl_vec<GnssSvInfo>& svInfoList) const {
     std::unique_lock<std::mutex> lock(mMutex);
+    // TODO(skz): update this to call 2_0 callback if non-null
     if (sGnssCallback_2_1 == nullptr) {
         ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
         return;
@@ -328,13 +334,20 @@
 
 void Gnss::reportLocation(const V2_0::GnssLocation& location) const {
     std::unique_lock<std::mutex> lock(mMutex);
-    if (sGnssCallback_2_1 == nullptr) {
-        ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
+    if (sGnssCallback_2_1 != nullptr) {
+        auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
+        if (!ret.isOk()) {
+            ALOGE("%s: Unable to invoke callback v2.1", __func__);
+        }
         return;
     }
-    auto ret = sGnssCallback_2_1->gnssLocationCb_2_0(location);
+    if (sGnssCallback_2_0 == nullptr) {
+        ALOGE("%s: No non-null callback", __func__);
+        return;
+    }
+    auto ret = sGnssCallback_2_0->gnssLocationCb_2_0(location);
     if (!ret.isOk()) {
-        ALOGE("%s: Unable to invoke callback", __func__);
+        ALOGE("%s: Unable to invoke callback v2.0", __func__);
     }
 }
 
diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp
index ebfa7dd..34e20e5 100644
--- a/gnss/2.1/default/GnssMeasurement.cpp
+++ b/gnss/2.1/default/GnssMeasurement.cpp
@@ -29,7 +29,8 @@
 namespace V2_1 {
 namespace implementation {
 
-sp<V2_1::IGnssMeasurementCallback> GnssMeasurement::sCallback = nullptr;
+sp<V2_1::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_1 = nullptr;
+sp<V2_0::IGnssMeasurementCallback> GnssMeasurement::sCallback_2_0 = nullptr;
 
 GnssMeasurement::GnssMeasurement() : mMinIntervalMillis(1000) {}
 
@@ -48,7 +49,8 @@
     ALOGD("close");
     std::unique_lock<std::mutex> lock(mMutex);
     stop();
-    sCallback = nullptr;
+    sCallback_2_1 = nullptr;
+    sCallback_2_0 = nullptr;
     return Void();
 }
 
@@ -61,9 +63,18 @@
 
 // Methods from V2_0::IGnssMeasurement follow.
 Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0(
-        const sp<V2_0::IGnssMeasurementCallback>&, bool) {
-    // TODO implement
-    return V1_0::IGnssMeasurement::GnssMeasurementStatus{};
+        const sp<V2_0::IGnssMeasurementCallback>& callback, bool) {
+    ALOGD("setCallback_2_0");
+    std::unique_lock<std::mutex> lock(mMutex);
+    sCallback_2_0 = callback;
+
+    if (mIsActive) {
+        ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+        stop();
+    }
+    start();
+
+    return V1_0::IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
 }
 
 // Methods from V2_1::IGnssMeasurement follow.
@@ -71,7 +82,7 @@
         const sp<V2_1::IGnssMeasurementCallback>& callback, bool) {
     ALOGD("setCallback_2_1");
     std::unique_lock<std::mutex> lock(mMutex);
-    sCallback = callback;
+    sCallback_2_1 = callback;
 
     if (mIsActive) {
         ALOGW("GnssMeasurement callback already set. Resetting the callback...");
@@ -87,8 +98,13 @@
     mIsActive = true;
     mThread = std::thread([this]() {
         while (mIsActive == true) {
-            auto measurement = Utils::getMockMeasurementV2_1();
-            this->reportMeasurement(measurement);
+            if (sCallback_2_1 != nullptr) {
+                auto measurement = Utils::getMockMeasurementV2_1();
+                this->reportMeasurement(measurement);
+            } else {
+                auto measurement = Utils::getMockMeasurementV2_0();
+                this->reportMeasurement(measurement);
+            }
 
             std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
         }
@@ -103,14 +119,27 @@
     }
 }
 
+void GnssMeasurement::reportMeasurement(const GnssDataV2_0& data) {
+    ALOGD("reportMeasurement()");
+    std::unique_lock<std::mutex> lock(mMutex);
+    if (sCallback_2_0 == nullptr) {
+        ALOGE("%s: GnssMeasurement::sCallback_2_0 is null.", __func__);
+        return;
+    }
+    auto ret = sCallback_2_0->gnssMeasurementCb_2_0(data);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+    }
+}
+
 void GnssMeasurement::reportMeasurement(const GnssDataV2_1& data) {
     ALOGD("reportMeasurement()");
     std::unique_lock<std::mutex> lock(mMutex);
-    if (sCallback == nullptr) {
-        ALOGE("%s: GnssMeasurement::sCallback is null.", __func__);
+    if (sCallback_2_1 == nullptr) {
+        ALOGE("%s: GnssMeasurement::sCallback_2_1 is null.", __func__);
         return;
     }
-    auto ret = sCallback->gnssMeasurementCb_2_1(data);
+    auto ret = sCallback_2_1->gnssMeasurementCb_2_1(data);
     if (!ret.isOk()) {
         ALOGE("%s: Unable to invoke callback", __func__);
     }
diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/2.1/default/GnssMeasurement.h
index ee32903..3ed7bc5 100644
--- a/gnss/2.1/default/GnssMeasurement.h
+++ b/gnss/2.1/default/GnssMeasurement.h
@@ -30,6 +30,7 @@
 namespace implementation {
 
 using GnssDataV2_1 = V2_1::IGnssMeasurementCallback::GnssData;
+using GnssDataV2_0 = V2_0::IGnssMeasurementCallback::GnssData;
 
 using ::android::sp;
 using ::android::hardware::hidl_array;
@@ -62,9 +63,11 @@
   private:
     void start();
     void stop();
+    void reportMeasurement(const GnssDataV2_0&);
     void reportMeasurement(const GnssDataV2_1&);
 
-    static sp<IGnssMeasurementCallback> sCallback;
+    static sp<V2_1::IGnssMeasurementCallback> sCallback_2_1;
+    static sp<V2_0::IGnssMeasurementCallback> sCallback_2_0;
     std::atomic<long> mMinIntervalMillis;
     std::atomic<bool> mIsActive;
     std::thread mThread;
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.cpp b/gnss/2.1/default/GnssMeasurementCorrections.cpp
new file mode 100644
index 0000000..2bf5601
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurementCorrections.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GnssMeasurementCorrections"
+
+#include "GnssMeasurementCorrections.h"
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from V1_0::IMeasurementCorrections follow.
+Return<bool> GnssMeasurementCorrections::setCorrections(const MeasurementCorrections& corrections) {
+    ALOGD("setCorrections");
+    ALOGD("corrections = lat: %f, lng: %f, alt: %f, hUnc: %f, vUnc: %f, toa: %llu, "
+          "satCorrections.size: %d",
+          corrections.latitudeDegrees, corrections.longitudeDegrees, corrections.altitudeMeters,
+          corrections.horizontalPositionUncertaintyMeters,
+          corrections.verticalPositionUncertaintyMeters,
+          static_cast<unsigned long long>(corrections.toaGpsNanosecondsOfWeek),
+          static_cast<int>(corrections.satCorrections.size()));
+    for (auto singleSatCorrection : corrections.satCorrections) {
+        ALOGD("singleSatCorrection = flags: %d, constellation: %d, svid: %d, cfHz: %f, probLos: %f,"
+              " epl: %f, eplUnc: %f",
+              static_cast<int>(singleSatCorrection.singleSatCorrectionFlags),
+              static_cast<int>(singleSatCorrection.constellation),
+              static_cast<int>(singleSatCorrection.svid), singleSatCorrection.carrierFrequencyHz,
+              singleSatCorrection.probSatIsLos, singleSatCorrection.excessPathLengthMeters,
+              singleSatCorrection.excessPathLengthUncertaintyMeters);
+        ALOGD("reflecting plane = lat: %f, lng: %f, alt: %f, azm: %f",
+              singleSatCorrection.reflectingPlane.latitudeDegrees,
+              singleSatCorrection.reflectingPlane.longitudeDegrees,
+              singleSatCorrection.reflectingPlane.altitudeMeters,
+              singleSatCorrection.reflectingPlane.azimuthDegrees);
+    }
+
+    return true;
+}
+
+Return<bool> GnssMeasurementCorrections::setCallback(
+        const sp<V1_0::IMeasurementCorrectionsCallback>& callback) {
+    using Capabilities = V1_0::IMeasurementCorrectionsCallback::Capabilities;
+    auto ret =
+            callback->setCapabilitiesCb(Capabilities::LOS_SATS | Capabilities::EXCESS_PATH_LENGTH |
+                                        Capabilities::REFLECTING_PLANE);
+    if (!ret.isOk()) {
+        ALOGE("%s: Unable to invoke callback", __func__);
+        return false;
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace measurement_corrections
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gnss/2.1/default/GnssMeasurementCorrections.h b/gnss/2.1/default/GnssMeasurementCorrections.h
new file mode 100644
index 0000000..4339bed
--- /dev/null
+++ b/gnss/2.1/default/GnssMeasurementCorrections.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct GnssMeasurementCorrections : public IMeasurementCorrections {
+    // Methods from V1_0::IMeasurementCorrections follow.
+    Return<bool> setCorrections(const MeasurementCorrections& corrections) override;
+    Return<bool> setCallback(const sp<V1_0::IMeasurementCorrectionsCallback>& callback) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace measurement_corrections
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/allocator/4.0/IAllocator.hal b/graphics/allocator/4.0/IAllocator.hal
index 9931685..7934867 100644
--- a/graphics/allocator/4.0/IAllocator.hal
+++ b/graphics/allocator/4.0/IAllocator.hal
@@ -20,14 +20,6 @@
 
 interface IAllocator {
     /**
-     * Retrieves implementation-defined debug information, which will be
-     * displayed during, for example, `dumpsys SurfaceFlinger`.
-     *
-     * @return debugInfo is a string of debug information.
-     */
-    dumpDebugInfo() generates (string debugInfo);
-
-    /**
      * Allocates buffers with the properties specified by the descriptor.
      *
      * Allocations should be optimized for usage bits provided in the
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl
new file mode 100644
index 0000000..4fbc6b2
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Cta861_3.aidl
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * HDR static metadata extension as specified by CTA-861.3.
+ *
+ * This is an AIDL counterpart of the NDK struct `AHdrMetadata_cta861_3`.
+ */
+@VintfStability
+parcelable Cta861_3 {
+    /**
+     * Maximum content light level.
+     */
+    float maxContentLightLevel;
+    /**
+     * Maximum frame average light level.
+     */
+    float maxFrameAverageLightLevel;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
index 81a21ab..42cdd81 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/Dataspace.aidl
@@ -208,8 +208,6 @@
      */
     STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT
 
-
-
     TRANSFER_SHIFT = 22,
 
     /**
@@ -396,9 +394,7 @@
      * The values are encoded using the full range ([0,255] for 8-bit) for all
      * components.
      */
-    SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // deprecated, use V0_SRGB_LINEAR
-
-    V0_SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
+    SRGB_LINEAR = 1 << 16 | 1 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
 
 
     /**
@@ -413,7 +409,7 @@
      * Values beyond the range [0.0 - 1.0] would correspond to other colors
      * spaces and/or HDR content.
      */
-    V0_SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
+    SCRGB_LINEAR = 1 << 16 | 1 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
 
 
     /**
@@ -429,9 +425,7 @@
      *
      * Use full range and BT.709 standard.
      */
-    SRGB = 1 << 16 | 2 << 22 | 1 << 27, // deprecated, use V0_SRGB
-
-    V0_SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
+    SRGB = 1 << 16 | 2 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
 
 
     /**
@@ -446,7 +440,7 @@
      * Values beyond the range [0.0 - 1.0] would correspond to other colors
      * spaces and/or HDR content.
      */
-    V0_SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
+    SCRGB = 1 << 16 | 2 << 22 | 3 << 27, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
 
     /**
      * YCbCr Colorspaces
@@ -464,22 +458,18 @@
      *
      * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
      *
-     * Use full range, BT.601 transfer and BT.601_625 standard.
+     * Use full range, SMPTE 170M transfer and BT.601_625 standard.
      */
-    JFIF = 2 << 16 | 3 << 22 | 1 << 27, // deprecated, use V0_JFIF
-
-    V0_JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
+    JFIF = 2 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
 
     /**
      * ITU-R Recommendation 601 (BT.601) - 625-line
      *
      * Standard-definition television, 625 Lines (PAL)
      *
-     * Use limited range, BT.601 transfer and BT.601_625 standard.
+     * Use limited range, SMPTE 170M transfer and BT.601_625 standard.
      */
-    BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_625
-
-    V0_BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+    BT601_625 = 2 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
 
 
     /**
@@ -487,22 +477,18 @@
      *
      * Standard-definition television, 525 Lines (NTSC)
      *
-     * Use limited range, BT.601 transfer and BT.601_525 standard.
+     * Use limited range, SMPTE 170M transfer and BT.601_525 standard.
      */
-    BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT601_525
-
-    V0_BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+    BT601_525 = 4 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
 
     /**
      * ITU-R Recommendation 709 (BT.709)
      *
      * High-definition television
      *
-     * Use limited range, BT.709 transfer and BT.709 standard.
+     * Use limited range, SMPTE 170M transfer and BT.709 standard.
      */
-    BT709 = 1 << 16 | 3 << 22 | 2 << 27, // deprecated, use V0_BT709
-
-    V0_BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+    BT709 = 1 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
 
 
     /**
@@ -570,7 +556,7 @@
      *
      * Ultra High-definition television
      *
-     * Use full range, BT.709 transfer and BT2020 standard
+     * Use full range, SMPTE 170M transfer and BT2020 standard
      */
     BT2020 = 6 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL
 
@@ -622,7 +608,7 @@
      *
      * Ultra High-definition television
      *
-     * Use limited range, BT.709 transfer and BT2020 standard
+     * Use limited range, SMPTE 170M transfer and BT2020 standard
      */
     BT2020_ITU = 6 << 16 | 3 << 22 | 2 << 27, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_LIMITED
 
@@ -679,4 +665,13 @@
      * according to ISO/IEC 23008-12.
      */
     HEIF = 0x1004,
+
+    /**
+     * ITU-R Recommendation 709 (BT.709)
+     *
+     * High-definition television
+     *
+     * Use full range, SMPTE 170M transfer and BT.709 standard.
+     */
+    BT709_FULL_RANGE = 1 << 16 | 3 << 22 | 1 << 27, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_FULL
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl
new file mode 100644
index 0000000..60614cd
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/Smpte2086.aidl
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+import android.hardware.graphics.common.XyColor;
+
+/**
+ * Mastering display metadata as specified by SMPTE ST 2086.
+ *
+ * This is an AIDL counterpart of the NDK struct `AHdrMetadata_smpte2086`.
+ */
+@VintfStability
+parcelable Smpte2086 {
+    /**
+     * CIE XYZ chromaticity for red in the RGB primaries.
+     */
+    XyColor primaryRed;
+    /**
+     * CIE XYZ chromaticity for green in the RGB primaries.
+     */
+    XyColor primaryGreen;
+    /**
+     * CIE XYZ chromaticity for blue in the RGB primaries.
+     */
+    XyColor primaryBlue;
+    /**
+     * CIE XYZ chromaticity for the white point.
+     */
+    XyColor whitePoint;
+    /**
+     * Maximum luminance in candelas per square meter.
+     */
+    float maxLuminance;
+    /**
+     * Minimum luminance in candelas per square meter.
+     */
+    float minLuminance;
+}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 060d12c..43cf672 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -24,6 +24,15 @@
  *
  * IMapper@4.x must support getting the following standard buffer metadata types. IMapper@4.x may
  * support setting these standard buffer metadata types as well.
+ *
+ * When encoding these StandardMetadataTypes into a byte stream, the associated MetadataType is
+ * is first encoded followed by the StandardMetadataType value. The MetadataType is encoded by
+ * writing the length of MetadataType.name using 8 bytes in little endian, followed by a char
+ * array of MetadataType.name's characters. The char array is not null terminated. Finally,
+ * MetadataType.value is represented by 8 bytes written in little endian.
+ *
+ * The StandardMetadataType encode/decode support library can be found in:
+ * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
  */
 @VintfStability
 @Backing(type="long")
@@ -279,4 +288,43 @@
      * 4 bytes written in little endian.
      */
     BLEND_MODE = 17,
+
+    /**
+     * Can be used to get or set static HDR metadata specified by SMPTE ST 2086.
+     *
+     * This metadata is a stable aidl android.hardware.graphics.common.Smpte2086.
+     *
+     * This is not used in tone mapping until it has been set for the first time.
+     *
+     * When it is encoded into a byte stream, each float member is represented by 4 bytes written in
+     * little endian. The ordering of float values follows the definition of Smpte2086 and XyColor.
+     * If this is unset when encoded into a byte stream, the byte stream is empty.
+     */
+    SMPTE2086 = 18,
+
+    /**
+     * Can be used to get or set static HDR metadata specified by CTA 861.3.
+     *
+     * This metadata is a stable aidl android.hardware.graphics.common.Cta861_3.
+     *
+     * This is not used in tone mapping until it has been set for the first time.
+     *
+     * When it is encoded into a byte stream, each float member is represented by 4 bytes written in
+     * little endian. The ordering of float values follows the definition of Cta861_3.
+     * If this is unset when encoded into a byte stream, the byte stream is empty.
+     */
+    CTA861_3 = 19,
+
+    /**
+     * Can be used to get or set dynamic HDR metadata specified by SMPTE ST 2094-40:2016.
+     *
+     * This metadata is uint8_t byte array.
+     *
+     * This is not used in tone mapping until it has been set for the first time.
+     *
+     * When it is encoded into a byte stream, the length of the HDR metadata byte array is written
+     * using 8 bytes in little endian. It is followed by the uint8_t byte array.
+     * If this is unset when encoded into a byte stream, the byte stream is empty.
+     */
+    SMPTE2094_40 = 20,
 }
diff --git a/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl
new file mode 100644
index 0000000..9571273
--- /dev/null
+++ b/graphics/common/aidl/android/hardware/graphics/common/XyColor.aidl
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.common;
+
+/**
+ * Chromaticity based on 2 parameters.
+ *
+ * This is an AIDL counterpart of the NDK struct `AColor_xy`.
+ *
+ * @note This can be used to represent any 2-dimensional chromaticity.
+ */
+@VintfStability
+parcelable XyColor {
+    float x;
+    float y;
+}
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
index 03dfef1..93c85bd 100644
--- a/graphics/mapper/4.0/IMapper.hal
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -206,6 +206,9 @@
      * outside of @p accessRegion is undefined, except that it must not cause
      * process termination.
      *
+     * An accessRegion of all-zeros means the entire buffer. That is, it is
+     * equivalent to '(0,0)-(buffer width, buffer height)'.
+     *
      * This function can lock both single-planar and multi-planar formats. The caller
      * should use get() to get information about the buffer they are locking.
      * get() can be used to get information about the planes, offsets, stride,
@@ -478,7 +481,7 @@
      * particular Metadata field.
      *
      * The framework may attempt to set the following StandardMetadataType
-     * values: DATASPACE, PER_FRAME_METADATA, PER_FRAME_METADATA_BLOB and BLEND_MODE.
+     * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
      * We strongly encourage everyone to support setting as many of those fields as
      * possible. If a device's Composer implementation supports a field, it should be
      * supported here. Over time these metadata fields will be moved out of
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 8a5f54e..cb90fa0 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -71,13 +71,6 @@
     return mAllocator;
 }
 
-std::string Gralloc::dumpDebugInfo() {
-    std::string debugInfo;
-    mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
-
-    return debugInfo;
-}
-
 const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) {
     const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
     EXPECT_NE(nullptr, bufferHandle);
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index 1c635c4..cd40aa4 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -45,8 +45,6 @@
 
     sp<IAllocator> getAllocator() const;
 
-    std::string dumpDebugInfo();
-
     // When import is false, this simply calls IAllocator::allocate. When import
     // is true, the returned buffers are also imported into the mapper.
     //
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 7dc733c..2aad242 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -44,11 +44,13 @@
 using android::hardware::graphics::common::V1_2::PixelFormat;
 using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
 using aidl::android::hardware::graphics::common::BlendMode;
+using aidl::android::hardware::graphics::common::Cta861_3;
 using aidl::android::hardware::graphics::common::Dataspace;
 using aidl::android::hardware::graphics::common::ExtendableType;
 using aidl::android::hardware::graphics::common::PlaneLayout;
 using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
 using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using aidl::android::hardware::graphics::common::Smpte2086;
 using aidl::android::hardware::graphics::common::StandardMetadataType;
 
 using DecodeFunction = std::function<void(const IMapper::BufferDescriptorInfo& descriptorInfo,
@@ -306,13 +308,6 @@
 };
 
 /**
- * Test IAllocator::dumpDebugInfo by calling it.
- */
-TEST_P(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
-    mGralloc->dumpDebugInfo();
-}
-
-/**
  * Test IAllocator::allocate with valid buffer descriptors.
  */
 TEST_P(GraphicsMapperHidlTest, AllocatorAllocate) {
@@ -1027,6 +1022,42 @@
 }
 
 /**
+ * Test IMapper::get(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, GetSmpte2086) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<Smpte2086> smpte2086;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086));
+                EXPECT_FALSE(smpte2086.has_value());
+            });
+}
+
+/**
+ * Test IMapper::get(Cta861_3)
+ */
+TEST_P(GraphicsMapperHidlTest, GetCta861_3) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<Cta861_3> cta861_3;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3));
+                EXPECT_FALSE(cta861_3.has_value());
+            });
+}
+
+/**
+ * Test IMapper::get(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, GetSmpte2094_40) {
+    testGet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40,
+            [](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<std::vector<uint8_t>> smpte2094_40;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40));
+                EXPECT_FALSE(smpte2094_40.has_value());
+            });
+}
+
+/**
  * Test IMapper::get(metadata) with a bad buffer
  */
 TEST_P(GraphicsMapperHidlTest, GetMetadataBadValue) {
@@ -1079,6 +1110,15 @@
     ASSERT_EQ(Error::BAD_BUFFER,
               mGralloc->get(bufferHandle, gralloc4::MetadataType_BlendMode, &vec));
     ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2086, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_Cta861_3, &vec));
+    ASSERT_EQ(0, vec.size());
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, &vec));
+    ASSERT_EQ(0, vec.size());
 }
 
 /**
@@ -1406,7 +1446,7 @@
  * Test IMapper::set(Dataspace)
  */
 TEST_P(GraphicsMapperHidlTest, SetDataspace) {
-    Dataspace dataspace = Dataspace::V0_SRGB_LINEAR;
+    Dataspace dataspace = Dataspace::SRGB_LINEAR;
     hidl_vec<uint8_t> vec;
     ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &vec));
 
@@ -1435,6 +1475,90 @@
 }
 
 /**
+ * Test IMapper::set(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, SetSmpte2086) {
+    /**
+     * DISPLAY_P3 is a color space that uses the DCI_P3 primaries,
+     * the D65 white point and the SRGB transfer functions.
+     * Rendering Intent: Colorimetric
+     * Primaries:
+     *                  x       y
+     *  green           0.265   0.690
+     *  blue            0.150   0.060
+     *  red             0.680   0.320
+     *  white (D65)     0.3127  0.3290
+     */
+    std::optional<Smpte2086> smpte2086;
+    smpte2086->primaryRed.x = 0.680;
+    smpte2086->primaryRed.y = 0.320;
+    smpte2086->primaryGreen.x = 0.265;
+    smpte2086->primaryGreen.y = 0.690;
+    smpte2086->primaryBlue.x = 0.150;
+    smpte2086->primaryBlue.y = 0.060;
+    smpte2086->whitePoint.x = 0.3127;
+    smpte2086->whitePoint.y = 0.3290;
+    smpte2086->maxLuminance = 100.0;
+    smpte2086->minLuminance = 0.1;
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeSmpte2086(smpte2086, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<Smpte2086> realSmpte2086;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &realSmpte2086));
+                ASSERT_TRUE(realSmpte2086.has_value());
+                EXPECT_EQ(smpte2086->primaryRed.x, realSmpte2086->primaryRed.x);
+                EXPECT_EQ(smpte2086->primaryRed.y, realSmpte2086->primaryRed.y);
+                EXPECT_EQ(smpte2086->primaryGreen.x, realSmpte2086->primaryGreen.x);
+                EXPECT_EQ(smpte2086->primaryGreen.y, realSmpte2086->primaryGreen.y);
+                EXPECT_EQ(smpte2086->primaryBlue.x, realSmpte2086->primaryBlue.x);
+                EXPECT_EQ(smpte2086->primaryBlue.y, realSmpte2086->primaryBlue.y);
+                EXPECT_EQ(smpte2086->whitePoint.x, realSmpte2086->whitePoint.x);
+                EXPECT_EQ(smpte2086->whitePoint.y, realSmpte2086->whitePoint.y);
+                EXPECT_EQ(smpte2086->maxLuminance, realSmpte2086->maxLuminance);
+                EXPECT_EQ(smpte2086->minLuminance, realSmpte2086->minLuminance);
+            });
+}
+
+/**
+ * Test IMapper::set(Cta8613)
+ */
+TEST_P(GraphicsMapperHidlTest, SetCta861_3) {
+    std::optional<Cta861_3> cta861_3;
+    cta861_3->maxContentLightLevel = 78.0;
+    cta861_3->maxFrameAverageLightLevel = 62.0;
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(NO_ERROR, gralloc4::encodeCta861_3(cta861_3, &vec));
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<Cta861_3> realCta861_3;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &realCta861_3));
+                ASSERT_TRUE(realCta861_3.has_value());
+                EXPECT_EQ(cta861_3->maxContentLightLevel, realCta861_3->maxContentLightLevel);
+                EXPECT_EQ(cta861_3->maxFrameAverageLightLevel,
+                          realCta861_3->maxFrameAverageLightLevel);
+            });
+}
+
+/**
+ * Test IMapper::set(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, SetSmpte2094_40) {
+    hidl_vec<uint8_t> vec;
+
+    testSet(mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2094_40, vec,
+            [&](const IMapper::BufferDescriptorInfo& /*info*/, const hidl_vec<uint8_t>& vec) {
+                std::optional<std::vector<uint8_t>> realSmpte2094_40;
+                ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40));
+                EXPECT_FALSE(realSmpte2094_40.has_value());
+            });
+}
+
+/**
  * Test IMapper::set(metadata) with a bad buffer
  */
 TEST_P(GraphicsMapperHidlTest, SetMetadataNullBuffer) {
@@ -1469,6 +1593,11 @@
               mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
     ASSERT_EQ(Error::BAD_BUFFER,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
+    ASSERT_EQ(Error::BAD_BUFFER, mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
+    ASSERT_EQ(Error::BAD_BUFFER,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, vec));
 }
 
 /**
@@ -1528,6 +1657,10 @@
               mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, vec));
     ASSERT_EQ(Error::UNSUPPORTED,
               mGralloc->set(bufferHandle, gralloc4::MetadataType_BlendMode, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Smpte2086, vec));
+    ASSERT_EQ(Error::UNSUPPORTED,
+              mGralloc->set(bufferHandle, gralloc4::MetadataType_Cta861_3, vec));
 }
 
 /**
@@ -1760,6 +1893,45 @@
 }
 
 /**
+ * Test IMapper::getFromBufferDescriptorInfo(Smpte2086)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2086) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Smpte2086, &vec));
+
+    std::optional<Smpte2086> smpte2086;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2086(vec, &smpte2086));
+    EXPECT_FALSE(smpte2086.has_value());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Cta861_3)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoCta861_3) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->getFromBufferDescriptorInfo(
+                                   mDummyDescriptorInfo, gralloc4::MetadataType_Cta861_3, &vec));
+
+    std::optional<Cta861_3> cta861_3;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeCta861_3(vec, &cta861_3));
+    EXPECT_FALSE(cta861_3.has_value());
+}
+
+/**
+ * Test IMapper::getFromBufferDescriptorInfo(Smpte2094_40)
+ */
+TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoSmpte2094_40) {
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE,
+              mGralloc->getFromBufferDescriptorInfo(mDummyDescriptorInfo,
+                                                    gralloc4::MetadataType_Smpte2094_40, &vec));
+    std::optional<std::vector<uint8_t>> smpte2094_40;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodeSmpte2094_40(vec, &smpte2094_40));
+    EXPECT_FALSE(smpte2094_40.has_value());
+}
+
+/**
  * Test IMapper::getFromBufferDescriptorInfo(metadata) for unsupported metadata
  */
 TEST_P(GraphicsMapperHidlTest, GetFromBufferDescriptorInfoUnsupportedMetadata) {
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 35a2fb1..f78eb43 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -423,27 +423,33 @@
     EXPECT_EQ(ErrorCode::OK, error);
 
     if (avb_verification_enabled()) {
-        property_get("ro.boot.vbmeta.digest", property_value, "nogood");
-        EXPECT_NE(strcmp(property_value, "nogood"), 0);
+        EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
         string prop_string(property_value);
         EXPECT_EQ(prop_string.size(), 64);
         EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
 
-        property_get("ro.boot.vbmeta.device_state", property_value, "nogood");
-        EXPECT_NE(strcmp(property_value, "nogood"), 0);
+        EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
         if (!strcmp(property_value, "unlocked")) {
             EXPECT_FALSE(device_locked);
         } else {
             EXPECT_TRUE(device_locked);
         }
+
+        // Check that the expected result from VBMeta matches the build type. Only a user build
+        // should have AVB reporting the device is locked.
+        EXPECT_NE(property_get("ro.build.type", property_value, ""), 0);
+        if (!strcmp(property_value, "user")) {
+            EXPECT_TRUE(device_locked);
+        } else {
+            EXPECT_FALSE(device_locked);
+        }
     }
 
     // Verified boot key should be all 0's if the boot state is not verified or self signed
     std::string empty_boot_key(32, '\0');
     std::string verified_boot_key_str((const char*)verified_boot_key.data(),
                                       verified_boot_key.size());
-    property_get("ro.boot.verifiedbootstate", property_value, "nogood");
-    EXPECT_NE(property_value, "nogood");
+    EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
     if (!strcmp(property_value, "green")) {
         EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_VERIFIED);
         EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
@@ -546,7 +552,7 @@
         EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
         EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
             << "Key size " << key_size << "missing";
-        EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 3U));
+        EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
 
         CheckedDeleteKey(&key_blob);
     }
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index a3a3d90..fafc6e2 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -18,8 +18,10 @@
 
 import @1.2::DataRequestReason;
 import @1.4::IRadio;
+import @1.4::DataProfileInfo;
 import @1.5::AccessNetwork;
 import @1.5::DataProfileInfo;
+import @1.5::LinkAddress;
 import @1.5::NetworkScanRequest;
 import @1.5::RadioAccessSpecifier;
 import @1.5::SignalThresholdInfo;
@@ -149,12 +151,8 @@
      * @param reason The request reason. Must be DataRequestReason.NORMAL or
      *     DataRequestReason.HANDOVER.
      * @param addresses If the reason is DataRequestReason.HANDOVER, this indicates the list of link
-     *     addresses of the existing data connection. The format is IP address with optional "/"
-     *     prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
-     *     "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
-     *     the prefix length is absent, then the addresses are assumed to be point to point with
-     *     IPv4 with prefix length 32 or IPv6 with prefix length 128. This parameter must be ignored
-     *     unless reason is DataRequestReason.HANDOVER.
+     *     addresses of the existing data connection. This parameter must be ignored unless reason
+     *     is DataRequestReason.HANDOVER.
      * @param dnses If the reason is DataRequestReason.HANDOVER, this indicates the list of DNS
      *     addresses of the existing data connection. The format is defined in RFC-4291 section
      *     2.2. For example, "192.0.1.3" or "2001:db8::1". This parameter must be ignored unless
@@ -163,11 +161,11 @@
      * Response function is IRadioResponse.setupDataCallResponse_1_5()
      *
      * Note this API is the same as the 1.4 version except using the
-     * 1.5 AccessNetwork and DataProfileInto as the input param.
+     * 1.5 AccessNetwork, DataProfileInto, and link addresses as the input param.
      */
     oneway setupDataCall_1_5(int32_t serial, AccessNetwork accessNetwork,
             DataProfileInfo dataProfileInfo, bool roamingAllowed,
-            DataRequestReason reason, vec<string> addresses, vec<string> dnses);
+            DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses);
 
     /**
      * Set an apn to initial attach network
@@ -194,4 +192,31 @@
      * as the input param.
      */
     oneway setDataProfile_1_5(int32_t serial, vec<DataProfileInfo> profiles);
+
+    /**
+     * Toggle radio on and off (for "airplane" mode)
+     * If the radio is turned off/on the radio modem subsystem
+     * is expected return to an initialized state. For instance,
+     * any voice and data calls must be terminated and all associated
+     * lists emptied.
+     *
+     * When setting radio power on to exit from airplane mode to place an emergency call on this
+     * logical modem, powerOn, forEmergencyCall and preferredForEmergencyCall must be true. In
+     * this case, this modem is optimized to scan only emergency call bands, until:
+     * 1) Emergency call is completed; or
+     * 2) Another setRadioPower_1_5 is issued with forEmergencyCall being false or
+     * preferredForEmergencyCall being false; or
+     * 3) Timeout after a long period of time.
+     *
+     * @param serial Serial number of request.
+     * @param powerOn To turn on radio -> on = true, to turn off radio -> on = false.
+     * @param forEmergencyCall To indication to radio if this request is due to emergency call.
+     *      No effect if powerOn is false.
+     * @param preferredForEmergencyCall indicate whether the following emergency call will be sent
+     *      on this modem or not. No effect if forEmergencyCall is false, or powerOn is false.
+     *
+     * Response callback is IRadioConfigResponse. setRadioPowerResponse_1_5.
+     */
+    oneway setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
+            bool preferredForEmergencyCall);
 };
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index 11ec265..968948b 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -18,7 +18,7 @@
 
 import @1.0::RadioResponseInfo;
 import @1.4::IRadioResponse;
-import @1.4::SetupDataCallResult;
+import @1.5::SetupDataCallResult;
 
 /**
  * Interface declaring response functions to solicited radio requests.
@@ -135,4 +135,14 @@
      *   RadioError:SIM_ABSENT
      */
     oneway setDataProfileResponse_1_5(RadioResponseInfo info);
+
+    /**
+     * @param info Response info struct containing response type, serial no. and error
+     *
+     * Valid errors returned:
+     *   RadioError:NONE
+     *   RadioError:INTERNAL_ERR
+     *   RadioError:INVALID_ARGUMENTS
+     */
+    oneway setRadioPowerResponse_1_5(RadioResponseInfo info);
 };
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 5795f7b..73751b8 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -25,7 +25,10 @@
 import @1.2::NetworkScanRequest;
 import @1.4::AccessNetwork;
 import @1.4::ApnTypes;
+import @1.4::DataCallFailCause;
+import @1.4::DataConnActiveStatus;
 import @1.4::DataProfileInfo;
+import @1.4::PdpProtocolType;
 
 /**
  * Defining signal strength type.
@@ -289,3 +292,108 @@
     /** Supported APN types bitmap. See ApnTypes for the value of each bit. */
     bitfield<ApnTypes> supportedApnTypesBitmap;
 };
+
+/**
+ * The properties of the link address. This enum reflects the definition in
+ * if_addr.h in Linux kernel.
+ */
+enum AddressProperty : int32_t {
+    NONE = 0,
+
+    /** Indicates this address is deprecated */
+    DEPRECATED = 0x20,
+};
+
+/**
+ * Describes a data link address for mobile data connection.
+ */
+struct LinkAddress {
+    /**
+     * The format is IP address with optional "/"
+     * prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
+     * "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
+     * the prefix length is absent, then the addresses are assumed to be point to point with
+     * IPv4 with prefix length 32 or IPv6 with prefix length 128.
+     */
+    string address;
+
+    /**
+     * The properties of the link address
+     */
+    bitfield<AddressProperty> properties;
+
+    /**
+     * The UTC time that this link address will be deprecated. 0 indicates this information is not
+     * available.
+     */
+    uint64_t deprecatedTime;
+
+    /**
+     * The UTC time that this link address will expire and no longer valid. 0 indicates this
+     * information is not available.
+     */
+    uint64_t expiredTime;
+};
+
+/**
+ * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5
+ * version. In 1.5 the type of addresses changes to vector of LinkAddress.
+ */
+struct SetupDataCallResult {
+    /** Data call fail cause. DataCallFailCause.NONE if no error. */
+    DataCallFailCause cause;
+
+    /**
+     * If status != DataCallFailCause.NONE, this field indicates the suggested retry back-off timer
+     * value RIL wants to override the one pre-configured in FW. The unit is milliseconds.
+     * The value < 0 means no value is suggested.
+     * The value 0 means retry must be done ASAP.
+     * The value of INT_MAX(0x7fffffff) means no retry.
+     */
+    int32_t suggestedRetryTime;
+
+    /** Context ID, uniquely identifies this call. */
+    int32_t cid;
+
+    /** Data connection active status. */
+    DataConnActiveStatus active;
+
+    /**
+     * PDP_type values. If cause is DataCallFailCause.ONLY_SINGLE_BEARER_ALLOWED, this is the type
+     * supported such as "IP" or "IPV6".
+     */
+    PdpProtocolType type;
+
+    /** The network interface name. */
+    string ifname;
+
+    /**
+     * List of link address.
+     */
+    vec<LinkAddress> addresses;
+
+    /**
+     * List of DNS server addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1". Empty if no dns
+     * server addresses returned.
+     */
+    vec<string> dnses;
+
+    /**
+     * List of default gateway addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+     * When empty, the addresses represent point to point connections.
+     */
+    vec<string> gateways;
+
+    /**
+     * List of P-CSCF(Proxy Call State Control Function) addresses via PCO(Protocol Configuration
+     * Option), e.g., "2001:db8::1 2001:db8::2 2001:db8::3". Empty if not IMS client.
+     */
+    vec<string> pcscf;
+
+    /**
+     * MTU received from network. Value <= 0 means network has either not sent a value or sent an
+     * invalid value.
+     */
+    int32_t mtu;
+};
+
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 1243bed..77d9a02 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -853,10 +853,11 @@
 
     bool roamingAllowed = false;
 
+    std::vector<::android::hardware::radio::V1_5::LinkAddress> addresses = {};
+    std::vector<hidl_string> dnses = {};
+
     ::android::hardware::radio::V1_2::DataRequestReason reason =
             ::android::hardware::radio::V1_2::DataRequestReason::NORMAL;
-    std::vector<hidl_string> addresses = {""};
-    std::vector<hidl_string> dnses = {""};
 
     Return<void> res = radio_v1_5->setupDataCall_1_5(serial, accessNetwork, dataProfileInfo,
                                                      roamingAllowed, reason, addresses, dnses);
@@ -958,3 +959,31 @@
                                      {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
     }
 }
+
+TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancalled) {
+    // Set radio power to off.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->setRadioPower_1_5(serial, false, false, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    // Set radio power to on with forEmergencyCall being true. This should put modem to only scan
+    // emergency call bands.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->setRadioPower_1_5(serial, true, true, true);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    // Set radio power to on with forEmergencyCall being false. This should put modem in regular
+    // operation modem.
+    serial = GetRandomSerialNumber();
+    radio_v1_5->setRadioPower_1_5(serial, true, false, false);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+}
\ No newline at end of file
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index f7526d9..ba11257 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -544,11 +544,13 @@
 
     Return<void> setupDataCallResponse_1_5(
             const RadioResponseInfo& info,
-            const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse);
+            const android::hardware::radio::V1_5::SetupDataCallResult& dcResponse);
 
     Return<void> setInitialAttachApnResponse_1_5(const RadioResponseInfo& info);
 
     Return<void> setDataProfileResponse_1_5(const RadioResponseInfo& info);
+
+    Return<void> setRadioPowerResponse_1_5(const RadioResponseInfo& info);
 };
 
 /* Callback class for radio indication */
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index 5dee191..a0b3d5f 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -931,7 +931,7 @@
 
 Return<void> RadioResponse_v1_5::setupDataCallResponse_1_5(
         const RadioResponseInfo& info,
-        const android::hardware::radio::V1_4::SetupDataCallResult& /* dcResponse */) {
+        const android::hardware::radio::V1_5::SetupDataCallResult& /* dcResponse */) {
     rspInfo = info;
     parent_v1_5.notify(info.serial);
     return Void();
@@ -948,3 +948,9 @@
     parent_v1_5.notify(info.serial);
     return Void();
 }
+
+Return<void> RadioResponse_v1_5::setRadioPowerResponse_1_5(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
\ No newline at end of file
diff --git a/rebootescrow/aidl/Android.bp b/rebootescrow/aidl/Android.bp
new file mode 100644
index 0000000..7bc8d6f
--- /dev/null
+++ b/rebootescrow/aidl/Android.bp
@@ -0,0 +1,18 @@
+aidl_interface {
+    name: "vintf-rebootescrow",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/rebootescrow/IRebootEscrow.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            platform_apis: true,
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+        },
+    },
+}
diff --git a/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl b/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl
new file mode 100644
index 0000000..edc695d
--- /dev/null
+++ b/rebootescrow/aidl/android/hardware/rebootescrow/IRebootEscrow.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.rebootescrow;
+
+/**
+ * This HAL defines the interface to the device-specific implementation
+ * of retaining a secret to unlock the Synthetic Password stored during
+ * a reboot to perform an OTA update. The implementation of this interface
+ * should never store the key on any non-volatile medium. The key should be
+ * overwritten with zeroes when destroyKey() is called. All care should be given
+ * to provide the shortest lifetime for the storage of the key in volatile and
+ * erasable storage.
+ *
+ * This HAL is optional so does not require an implementation on device.
+ */
+@VintfStability
+interface IRebootEscrow {
+    /**
+     * Store the key for reboot.
+     */
+    void storeKey(in byte[] kek);
+
+    /**
+     * Retrieve the possible keys. If the implementation is probabalistic, it
+     * should return the keys in order from most-probable to least-probable.
+     * There is not a hard limit to the number of keys, but it is suggested to
+     * keep the number of key possibilities less than 32.
+     */
+    byte[] retrieveKey();
+}
diff --git a/rebootescrow/aidl/default/Android.bp b/rebootescrow/aidl/default/Android.bp
new file mode 100644
index 0000000..c8cbf48
--- /dev/null
+++ b/rebootescrow/aidl/default/Android.bp
@@ -0,0 +1,88 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "librebootescrowdefaultimpl",
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "vintf-rebootescrow-ndk_platform",
+    ],
+    export_include_dirs: ["include"],
+    srcs: [
+        "RebootEscrow.cpp",
+    ],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.rebootescrow-service.default",
+    init_rc: ["rebootescrow-default.rc"],
+    relative_install_path: "hw",
+    vintf_fragments: ["rebootescrow-default.xml"],
+    vendor: true,
+    srcs: [
+        "service.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "vintf-rebootescrow-ndk_platform",
+    ],
+    static_libs: [
+        "libhadamardutils",
+        "librebootescrowdefaultimpl",
+    ],
+}
+
+cc_library_static {
+    name: "libhadamardutils",
+    vendor_available: true,
+    host_supported: true,
+    shared_libs: [
+        "libbase",
+    ],
+    srcs: [
+        "HadamardUtils.cpp",
+    ],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
+cc_test {
+    name: "HadamardUtilsTest",
+    host_supported: true,
+    srcs: [
+        "HadamardUtilsTest.cpp",
+    ],
+    static_libs: [
+        "libhadamardutils",
+        "libgtest_prod",
+    ],
+    shared_libs: [
+        "liblog",
+        "libbase",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp
new file mode 100644
index 0000000..5853d2d
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtils.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <HadamardUtils.h>
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+namespace hadamard {
+
+constexpr auto BYTE_LENGTH = 8u;
+
+std::vector<uint8_t> BitsetToBytes(const std::bitset<ENCODE_LENGTH>& encoded_bits) {
+    CHECK_EQ(0, (encoded_bits.size() % BYTE_LENGTH));
+    std::vector<uint8_t> result;
+    for (size_t i = 0; i < encoded_bits.size(); i += 8) {
+        uint8_t current = 0;
+        // Set each byte starting from the LSB.
+        for (size_t j = 0; j < BYTE_LENGTH; j++) {
+            CHECK_LE(i + j, encoded_bits.size());
+            if (encoded_bits[i + j]) {
+                current |= (1u << j);
+            }
+        }
+        result.push_back(current);
+    }
+    return result;
+}
+
+std::bitset<ENCODE_LENGTH> BytesToBitset(const std::vector<uint8_t>& encoded) {
+    CHECK_EQ(ENCODE_LENGTH, encoded.size() * BYTE_LENGTH);
+
+    std::bitset<ENCODE_LENGTH> result;
+    size_t offset = 0;
+    for (const auto& byte : encoded) {
+        // Set each byte starting from the LSB.
+        for (size_t j = 0; j < BYTE_LENGTH; j++) {
+            result[offset + j] = byte & (1u << j);
+        }
+        offset += BYTE_LENGTH;
+    }
+    return result;
+}
+
+// The encoding is equivalent to multiply the word with the generator matrix (and take the module
+// of 2). Here is an example of encoding a number with 3 bits. The encoded length is thus
+// 2^(3-1) = 4 bits.
+//              |1 1 1 1|     |0|
+//  |0 1 1|  *  |0 0 1 1|  =  |1|
+//              |0 1 0 1|     |1|
+//                            |0|
+std::bitset<ENCODE_LENGTH> EncodeWord(uint16_t word) {
+    std::bitset<ENCODE_LENGTH> result;
+    for (uint64_t i = ENCODE_LENGTH; i < 2 * ENCODE_LENGTH; i++) {
+        uint32_t wi = word & i;
+        // Sum all the bits in the word and check its parity.
+        wi ^= wi >> 8u;
+        wi ^= wi >> 4u;
+        wi ^= wi >> 2u;
+        wi ^= wi >> 1u;
+        result[i - ENCODE_LENGTH] = wi & 1u;
+    }
+    return result;
+}
+
+std::vector<uint8_t> EncodeKey(const std::vector<uint8_t>& key) {
+    CHECK_EQ(KEY_SIZE_IN_BYTES, key.size());
+
+    std::vector<uint8_t> result;
+    for (size_t i = 0; i < key.size(); i += 2) {
+        uint16_t word = static_cast<uint16_t>(key[i + 1]) << BYTE_LENGTH | key[i];
+        auto encoded_bits = EncodeWord(word);
+        auto byte_array = BitsetToBytes(encoded_bits);
+        std::move(byte_array.begin(), byte_array.end(), std::back_inserter(result));
+    }
+    return result;
+}
+
+std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& encoded) {
+    CHECK_EQ(0, (encoded.size() * 8) % ENCODE_LENGTH);
+    std::vector<uint8_t> result;
+    for (size_t i = 0; i < encoded.size(); i += ENCODE_LENGTH / 8) {
+        auto current =
+                std::vector<uint8_t>{encoded.begin() + i, encoded.begin() + i + ENCODE_LENGTH / 8};
+        auto bits = BytesToBitset(current);
+        auto candidates = DecodeWord(bits);
+        CHECK(!candidates.empty());
+        // TODO(xunchang) Do we want to try other candidates?
+        uint16_t val = candidates.top().second;
+        result.push_back(val & 0xffu);
+        result.push_back(val >> BYTE_LENGTH);
+    }
+
+    return result;
+}
+
+std::priority_queue<std::pair<int32_t, uint16_t>> DecodeWord(
+        const std::bitset<ENCODE_LENGTH>& encoded) {
+    std::vector<int32_t> scores;
+    scores.reserve(ENCODE_LENGTH);
+    // Convert 0 -> -1 in the encoded bits. e.g [0, 1, 1, 0] -> [-1, 1, 1, -1]
+    for (uint32_t i = 0; i < ENCODE_LENGTH; i++) {
+        scores.push_back(2 * encoded[i] - 1);
+    }
+
+    // Multiply the hadamard matrix by the transformed input.
+    // |1  1  1  1|     |-1|     | 0|
+    // |1 -1  1 -1|  *  | 1|  =  | 0|
+    // |1  1 -1 -1|     | 1|     | 0|
+    // |1 -1 -1  1|     |-1|     |-4|
+    for (uint32_t i = 0; i < CODE_K; i++) {
+        uint16_t step = 1u << i;
+        for (uint32_t j = 0; j < ENCODE_LENGTH; j += 2 * step) {
+            for (uint32_t k = j; k < j + step; k++) {
+                auto a0 = scores[k];
+                auto a1 = scores[k + step];
+                scores[k] = a0 + a1;
+                scores[k + step] = a0 - a1;
+            }
+        }
+    }
+
+    // Assign the corresponding score to each index; larger score indicates higher probability. e.g.
+    // value 3, encoding [0, 1, 1, 0] -> score: 4
+    // value 7, encoding [1, 0, 0, 1] (3's complement) -> score: -4
+    std::priority_queue<std::pair<int32_t, uint16_t>> candidates;
+    // TODO(xunchang) limit the candidate size since we don't need all of them?
+    for (uint32_t i = 0; i < scores.size(); i++) {
+        candidates.emplace(-scores[i], i);
+        candidates.emplace(scores[i], (1u << CODE_K) | i);
+    }
+
+    CHECK_EQ(2 * ENCODE_LENGTH, candidates.size());
+    return candidates;
+}
+
+}  // namespace hadamard
+}  // namespace rebootescrow
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/rebootescrow/aidl/default/HadamardUtils.h b/rebootescrow/aidl/default/HadamardUtils.h
new file mode 100644
index 0000000..21cfc78
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtils.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <bitset>
+#include <queue>
+#include <utility>
+#include <vector>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+namespace hadamard {
+
+constexpr uint32_t CODE_K = 15;
+constexpr uint32_t ENCODE_LENGTH = 1u << CODE_K;
+constexpr auto KEY_SIZE_IN_BYTES = 32u;
+
+// Encodes a 2 bytes word with hadamard code. The encoding expands a word of k+1 bits to a 2^k
+// bitset. Returns the encoded bitset.
+std::bitset<ENCODE_LENGTH> EncodeWord(uint16_t word);
+
+// Decodes the input bitset, and returns a sorted list of pair with (score, value). The value with
+// a higher score indicates a greater likehood.
+std::priority_queue<std::pair<int32_t, uint16_t>> DecodeWord(
+        const std::bitset<ENCODE_LENGTH>& encoded);
+
+// Encodes a key that has a size of KEY_SIZE_IN_BYTES. Returns a byte array representation of the
+// encoded bitset. So a 32 bytes key will expand to 16*(2^15) bits = 64KiB.
+std::vector<uint8_t> EncodeKey(const std::vector<uint8_t>& input);
+
+// Given a byte array representation of the encoded keys, decodes it and return the result.
+std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& encoded);
+
+// Converts a bitset of length |ENCODE_LENGTH| to a byte array.
+std::vector<uint8_t> BitsetToBytes(const std::bitset<ENCODE_LENGTH>& encoded_bits);
+
+// Converts a byte array of encoded words back to the bitset.
+std::bitset<ENCODE_LENGTH> BytesToBitset(const std::vector<uint8_t>& encoded);
+
+}  // namespace hadamard
+}  // namespace rebootescrow
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/rebootescrow/aidl/default/HadamardUtilsTest.cpp b/rebootescrow/aidl/default/HadamardUtilsTest.cpp
new file mode 100644
index 0000000..e397e76
--- /dev/null
+++ b/rebootescrow/aidl/default/HadamardUtilsTest.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <random>
+
+#include <bitset>
+#include <utility>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <HadamardUtils.h>
+
+using namespace aidl::android::hardware::rebootescrow::hadamard;
+
+class HadamardTest : public testing::Test {
+  protected:
+    void SetUp() override {
+        auto ones = std::bitset<ENCODE_LENGTH>{}.set();
+        // Expects 0x4000 to encode as top half as ones, and lower half as zeros. i.e.
+        // [1, 1 .. 1, 0, 0 .. 0]
+        expected_half_size_ = ones << half_size_;
+
+        // Expects 0x1 to encode as interleaved 1 and 0s  i.e. [1, 0, 1, 0 ..]
+        expected_one_ = ones;
+        for (uint32_t i = ENCODE_LENGTH / 2; i >= 1; i /= 2) {
+            expected_one_ ^= (expected_one_ >> i);
+        }
+    }
+
+    uint16_t half_size_ = ENCODE_LENGTH / 2;
+    std::bitset<ENCODE_LENGTH> expected_one_;
+    std::bitset<ENCODE_LENGTH> expected_half_size_;
+};
+
+static void AddError(std::bitset<ENCODE_LENGTH>* corrupted_bits) {
+    // The hadamard code has a hamming distance of ENCODE_LENGTH/2. So we should always be able to
+    // correct the data if less than a quarter of the encoded bits are corrupted.
+    auto corrupted_max = 0.24f * corrupted_bits->size();
+    auto corrupted_num = 0;
+    for (size_t i = 0; i < corrupted_bits->size() && corrupted_num < corrupted_max; i++) {
+        if (random() % 2 == 0) {
+            (*corrupted_bits)[i] = !(*corrupted_bits)[i];
+            corrupted_num += 1;
+        }
+    }
+}
+
+static void EncodeAndDecodeKeys(const std::vector<uint8_t>& key) {
+    auto encoded = EncodeKey(key);
+    ASSERT_EQ(64 * 1024, encoded.size());
+    auto decoded = DecodeKey(encoded);
+    ASSERT_EQ(key, std::vector<uint8_t>(decoded.begin(), decoded.begin() + key.size()));
+}
+
+TEST_F(HadamardTest, Encode_smoke) {
+    ASSERT_EQ(expected_half_size_, EncodeWord(half_size_));
+    ASSERT_EQ(expected_one_, EncodeWord(1));
+    // Check the complement of 1.
+    ASSERT_EQ(~expected_one_, EncodeWord(1u << CODE_K | 1u));
+}
+
+TEST_F(HadamardTest, Decode_smoke) {
+    auto candidate = DecodeWord(expected_half_size_);
+    auto expected = std::pair<int32_t, uint16_t>{ENCODE_LENGTH, half_size_};
+    ASSERT_EQ(expected, candidate.top());
+
+    candidate = DecodeWord(expected_one_);
+    expected = std::pair<int32_t, uint16_t>{ENCODE_LENGTH, 1};
+    ASSERT_EQ(expected, candidate.top());
+}
+
+TEST_F(HadamardTest, Decode_error_correction) {
+    constexpr auto iteration = 10;
+    for (int i = 0; i < iteration; i++) {
+        uint16_t word = random() % (ENCODE_LENGTH * 2);
+        auto corrupted_bits = EncodeWord(word);
+        AddError(&corrupted_bits);
+
+        auto candidate = DecodeWord(corrupted_bits);
+        ASSERT_EQ(word, candidate.top().second);
+    }
+}
+
+TEST_F(HadamardTest, BytesToBitset_smoke) {
+    auto bytes = BitsetToBytes(expected_one_);
+
+    auto read_back = BytesToBitset(bytes);
+    ASSERT_EQ(expected_one_, read_back);
+}
+
+TEST_F(HadamardTest, EncodeAndDecodeKey) {
+    std::vector<uint8_t> KEY_1{
+            0xA5, 0x00, 0xFF, 0x01, 0xA5, 0x5a, 0xAA, 0x55, 0x00, 0xD3, 0x2A,
+            0x8C, 0x2E, 0x83, 0x0E, 0x65, 0x9E, 0x8D, 0xC6, 0xAC, 0x1E, 0x83,
+            0x21, 0xB3, 0x95, 0x02, 0x89, 0x64, 0x64, 0x92, 0x12, 0x1F,
+    };
+    std::vector<uint8_t> KEY_2{
+            0xFF, 0x00, 0x00, 0xAA, 0x5A, 0x19, 0x20, 0x71, 0x9F, 0xFB, 0xDA,
+            0xB6, 0x2D, 0x06, 0xD5, 0x49, 0x7E, 0xEF, 0x63, 0xAC, 0x18, 0xFF,
+            0x5A, 0xA3, 0x40, 0xBB, 0x64, 0xFA, 0x67, 0xC1, 0x10, 0x18,
+    };
+
+    EncodeAndDecodeKeys(KEY_1);
+    EncodeAndDecodeKeys(KEY_2);
+
+    std::vector<uint8_t> key;
+    for (uint8_t i = 0; i < KEY_SIZE_IN_BYTES; i++) {
+        key.push_back(i);
+    };
+    EncodeAndDecodeKeys(key);
+}
diff --git a/rebootescrow/aidl/default/RebootEscrow.cpp b/rebootescrow/aidl/default/RebootEscrow.cpp
new file mode 100644
index 0000000..94d0901
--- /dev/null
+++ b/rebootescrow/aidl/default/RebootEscrow.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+#include "HadamardUtils.h"
+#include "rebootescrow-impl/RebootEscrow.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+
+using ::android::base::unique_fd;
+
+ndk::ScopedAStatus RebootEscrow::storeKey(const std::vector<int8_t>& kek) {
+    int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
+    unique_fd fd(rawFd);
+    if (fd.get() < 0) {
+        LOG(WARNING) << "Could not open reboot escrow device";
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    std::vector<uint8_t> ukek(kek.begin(), kek.end());
+    auto encoded = hadamard::EncodeKey(ukek);
+
+    if (!::android::base::WriteFully(fd, encoded.data(), encoded.size())) {
+        LOG(WARNING) << "Could not write data fully to character device";
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RebootEscrow::retrieveKey(std::vector<int8_t>* _aidl_return) {
+    int rawFd = TEMP_FAILURE_RETRY(::open(REBOOT_ESCROW_DEVICE, O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
+    unique_fd fd(rawFd);
+    if (fd.get() < 0) {
+        LOG(WARNING) << "Could not open reboot escrow device";
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    std::string encodedString;
+    if (!::android::base::ReadFdToString(fd, &encodedString)) {
+        LOG(WARNING) << "Could not read device to string";
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    std::vector<uint8_t> encodedBytes(encodedString.begin(), encodedString.end());
+    auto keyBytes = hadamard::DecodeKey(encodedBytes);
+
+    std::vector<int8_t> signedKeyBytes(keyBytes.begin(), keyBytes.end());
+    *_aidl_return = signedKeyBytes;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace rebootescrow
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
new file mode 100644
index 0000000..1ed7397
--- /dev/null
+++ b/rebootescrow/aidl/default/include/rebootescrow-impl/RebootEscrow.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/rebootescrow/BnRebootEscrow.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace rebootescrow {
+
+static const char* REBOOT_ESCROW_DEVICE = "/dev/access-kregistry";
+
+class RebootEscrow : public BnRebootEscrow {
+    ndk::ScopedAStatus storeKey(const std::vector<int8_t>& kek) override;
+    ndk::ScopedAStatus retrieveKey(std::vector<int8_t>* _aidl_return) override;
+};
+
+}  // namespace rebootescrow
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/rebootescrow/aidl/default/rebootescrow-default.rc b/rebootescrow/aidl/default/rebootescrow-default.rc
new file mode 100644
index 0000000..e7a9cfc
--- /dev/null
+++ b/rebootescrow/aidl/default/rebootescrow-default.rc
@@ -0,0 +1,9 @@
+service vendor.rebootescrow-default /vendor/bin/hw/android.hardware.rebootescrow-service.default
+    interface aidl android.hardware.rebootescrow.IRebootEscrow/default
+    class hal
+    user system
+    group system
+
+on boot
+    chmod 770 /dev/access-kregistry
+    chown system system /dev/access-kregistry
diff --git a/rebootescrow/aidl/default/rebootescrow-default.xml b/rebootescrow/aidl/default/rebootescrow-default.xml
new file mode 100644
index 0000000..0499fcc
--- /dev/null
+++ b/rebootescrow/aidl/default/rebootescrow-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.rebootescrow</name>
+        <fqname>IRebootEscrow/default</fqname>
+    </hal>
+</manifest>
diff --git a/rebootescrow/aidl/default/service.cpp b/rebootescrow/aidl/default/service.cpp
new file mode 100644
index 0000000..bd2378e
--- /dev/null
+++ b/rebootescrow/aidl/default/service.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "rebootescrow-impl/RebootEscrow.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::rebootescrow::RebootEscrow;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    auto re = ndk::SharedRefBase::make<RebootEscrow>();
+    const std::string instance = std::string() + RebootEscrow::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(re->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;
+}
diff --git a/rebootescrow/aidl/vts/functional/Android.bp b/rebootescrow/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..dadf250
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalRebootEscrowTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalRebootEscrowTargetTest.cpp"],
+    shared_libs: [
+        "libbinder",
+    ],
+    static_libs: [
+        "vintf-rebootescrow-cpp",
+    ],
+    test_suites: [
+        "vts-core",
+    ],
+    require_root: true,
+}
diff --git a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
new file mode 100644
index 0000000..f69cf87
--- /dev/null
+++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android/hardware/rebootescrow/BnRebootEscrow.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+using android::sp;
+using android::String16;
+using android::hardware::rebootescrow::IRebootEscrow;
+
+/**
+ * This tests that the key can be written, read, and removed. It does not test
+ * that the key survives a reboot. That needs a host-based test.
+ *
+ * atest VtsHalRebootEscrowV1_0TargetTest
+ */
+class RebootEscrowAidlTest : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        rebootescrow = android::waitForDeclaredService<IRebootEscrow>(String16(GetParam().c_str()));
+        ASSERT_NE(rebootescrow, nullptr);
+    }
+
+    sp<IRebootEscrow> rebootescrow;
+
+    std::vector<uint8_t> KEY_1{
+            0xA5, 0x00, 0xFF, 0x01, 0xA5, 0x5a, 0xAA, 0x55, 0x00, 0xD3, 0x2A,
+            0x8C, 0x2E, 0x83, 0x0E, 0x65, 0x9E, 0x8D, 0xC6, 0xAC, 0x1E, 0x83,
+            0x21, 0xB3, 0x95, 0x02, 0x89, 0x64, 0x64, 0x92, 0x12, 0x1F,
+    };
+    std::vector<uint8_t> KEY_2{
+            0xFF, 0x00, 0x00, 0xAA, 0x5A, 0x19, 0x20, 0x71, 0x9F, 0xFB, 0xDA,
+            0xB6, 0x2D, 0x06, 0xD5, 0x49, 0x7E, 0xEF, 0x63, 0xAC, 0x18, 0xFF,
+            0x5A, 0xA3, 0x40, 0xBB, 0x64, 0xFA, 0x67, 0xC1, 0x10, 0x18,
+    };
+    std::vector<uint8_t> EMPTY_KEY{
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    };
+};
+
+TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_Success) {
+    ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+
+    std::vector<uint8_t> actualKey;
+    ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+    EXPECT_EQ(actualKey, KEY_1);
+}
+
+TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_SecondRetrieveSucceeds) {
+    ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+
+    std::vector<uint8_t> actualKey;
+    ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+    EXPECT_EQ(actualKey, KEY_1);
+
+    ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+    EXPECT_EQ(actualKey, KEY_1);
+}
+
+TEST_P(RebootEscrowAidlTest, StoreTwiceOverwrites_Success) {
+    ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
+    ASSERT_TRUE(rebootescrow->storeKey(KEY_2).isOk());
+
+    std::vector<uint8_t> actualKey;
+    ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+    EXPECT_EQ(actualKey, KEY_2);
+}
+
+TEST_P(RebootEscrowAidlTest, StoreEmpty_AfterGetEmptyKey_Success) {
+    rebootescrow->storeKey(KEY_1);
+    rebootescrow->storeKey(EMPTY_KEY);
+
+    std::vector<uint8_t> actualKey;
+    ASSERT_TRUE(rebootescrow->retrieveKey(&actualKey).isOk());
+    EXPECT_EQ(actualKey, EMPTY_KEY);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        RebootEscrow, RebootEscrowAidlTest,
+        testing::ValuesIn(android::getAidlHalInstanceNames(IRebootEscrow::descriptor)),
+        android::PrintInstanceNameToString);
diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal
index 3ed09f6..94e3c0c 100644
--- a/tv/tuner/1.0/IFilter.hal
+++ b/tv/tuner/1.0/IFilter.hal
@@ -104,11 +104,11 @@
      *
      * It is used by the client to ask the hardware resource id for the filter.
      *
-     * @param filterId the hardware resource Id for the filter.
      * @return result Result status of the operation.
      *         SUCCESS if successful,
      *         INVALID_STATE if failed for wrong state.
      *         UNKNOWN_ERROR if failed for other reasons.
+     * @return filterId the hardware resource Id for the filter.
      */
     getId() generates (Result result, uint32_t filterId);
 
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index 71a26ab..43c4e3a 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -51,7 +51,8 @@
     mFrontendSourceFile = mFrontend->getSourceFile();
 
     mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
-    return startBroadcastInputLoop();
+
+    return startFrontendInputLoop();
 }
 
 Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
@@ -136,14 +137,14 @@
         return Void();
     }
 
-    sp<Dvr> dvr = new Dvr(type, bufferSize, cb, this);
+    mDvr = new Dvr(type, bufferSize, cb, this);
 
-    if (!dvr->createDvrMQ()) {
-        _hidl_cb(Result::UNKNOWN_ERROR, dvr);
+    if (!mDvr->createDvrMQ()) {
+        _hidl_cb(Result::UNKNOWN_ERROR, mDvr);
         return Void();
     }
 
-    _hidl_cb(Result::SUCCESS, dvr);
+    _hidl_cb(Result::SUCCESS, mDvr);
     return Void();
 }
 
@@ -166,13 +167,14 @@
 
     // resetFilterRecords(filterId);
     mUsedFilterIds.erase(filterId);
+    mRecordFilterIds.erase(filterId);
     mUnusedFilterIds.insert(filterId);
     mFilters.erase(filterId);
 
     return Result::SUCCESS;
 }
 
-void Demux::startTsFilter(vector<uint8_t> data) {
+void Demux::startBroadcastTsFilter(vector<uint8_t> data) {
     set<uint32_t>::iterator it;
     for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
         uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
@@ -185,7 +187,17 @@
     }
 }
 
-bool Demux::startFilterDispatcher() {
+void Demux::sendFrontendInputToRecord(vector<uint8_t> data) {
+    set<uint32_t>::iterator it;
+    for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+        if (DEBUG_FILTER) {
+            ALOGW("update record filter output");
+        }
+        mFilters[*it]->updateRecordOutput(data);
+    }
+}
+
+bool Demux::startBroadcastFilterDispatcher() {
     set<uint32_t>::iterator it;
 
     // Handle the output data per filter type
@@ -198,6 +210,18 @@
     return true;
 }
 
+bool Demux::startRecordFilterDispatcher() {
+    set<uint32_t>::iterator it;
+
+    for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+        if (mFilters[*it]->startRecordFilterHandler() != Result::SUCCESS) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
 Result Demux::startFilterHandler(uint32_t filterId) {
     return mFilters[filterId]->startFilterHandler();
 }
@@ -210,22 +234,22 @@
     return mFilters[filterId]->getTpid();
 }
 
-Result Demux::startBroadcastInputLoop() {
-    pthread_create(&mBroadcastInputThread, NULL, __threadLoopBroadcast, this);
-    pthread_setname_np(mBroadcastInputThread, "broadcast_input_thread");
+Result Demux::startFrontendInputLoop() {
+    pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
+    pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
 
     return Result::SUCCESS;
 }
 
-void* Demux::__threadLoopBroadcast(void* user) {
+void* Demux::__threadLoopFrontend(void* user) {
     Demux* const self = static_cast<Demux*>(user);
-    self->broadcastInputThreadLoop();
+    self->frontendInputThreadLoop();
     return 0;
 }
 
-void Demux::broadcastInputThreadLoop() {
-    std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
-    mBroadcastInputThreadRunning = true;
+void Demux::frontendInputThreadLoop() {
+    std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+    mFrontendInputThreadRunning = true;
     mKeepFetchingDataFromFrontend = true;
 
     // open the stream and get its length
@@ -234,20 +258,20 @@
     int packetSize = 188;
     int writePacketAmount = 6;
     char* buffer = new char[packetSize];
-    ALOGW("[Demux] broadcast input thread loop start %s", mFrontendSourceFile.c_str());
+    ALOGW("[Demux] Frontend input thread loop start %s", mFrontendSourceFile.c_str());
     if (!inputData.is_open()) {
-        mBroadcastInputThreadRunning = false;
+        mFrontendInputThreadRunning = false;
         ALOGW("[Demux] Error %s", strerror(errno));
     }
 
-    while (mBroadcastInputThreadRunning) {
+    while (mFrontendInputThreadRunning) {
         // move the stream pointer for packet size * 6 every read until the end
         while (mKeepFetchingDataFromFrontend) {
             for (int i = 0; i < writePacketAmount; i++) {
                 inputData.read(buffer, packetSize);
                 if (!inputData) {
                     mKeepFetchingDataFromFrontend = false;
-                    mBroadcastInputThreadRunning = false;
+                    mFrontendInputThreadRunning = false;
                     break;
                 }
                 // filter and dispatch filter output
@@ -256,23 +280,61 @@
                 for (int index = 0; index < byteBuffer.size(); index++) {
                     byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
                 }
-                startTsFilter(byteBuffer);
+                if (mIsRecording) {
+                    // Feed the data into the Dvr recording input
+                    sendFrontendInputToRecord(byteBuffer);
+                } else {
+                    // Feed the data into the broadcast demux filter
+                    startBroadcastTsFilter(byteBuffer);
+                }
             }
-            startFilterDispatcher();
+            if (mIsRecording) {
+                // Dispatch the data into the broadcasting filters.
+                startRecordFilterDispatcher();
+            } else {
+                // Dispatch the data into the broadcasting filters.
+                startBroadcastFilterDispatcher();
+            }
             usleep(100);
         }
     }
 
-    ALOGW("[Demux] Broadcast Input thread end.");
+    ALOGW("[Demux] Frontend Input thread end.");
     delete[] buffer;
     inputData.close();
 }
 
-void Demux::stopBroadcastInput() {
+void Demux::stopFrontendInput() {
     ALOGD("[Demux] stop frontend on demux");
     mKeepFetchingDataFromFrontend = false;
-    mBroadcastInputThreadRunning = false;
-    std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
+    mFrontendInputThreadRunning = false;
+    std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+}
+
+void Demux::setIsRecording(bool isRecording) {
+    mIsRecording = isRecording;
+}
+
+bool Demux::attachRecordFilter(int filterId) {
+    if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+        return false;
+    }
+
+    mRecordFilterIds.insert(filterId);
+    mFilters[filterId]->attachFilterToRecord(mDvr);
+
+    return true;
+}
+
+bool Demux::detachRecordFilter(int filterId) {
+    if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+        return false;
+    }
+
+    mRecordFilterIds.erase(filterId);
+    mFilters[filterId]->detachFilterFromRecord();
+
+    return true;
 }
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index 037429d..1405d0c 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -81,11 +81,14 @@
     virtual Return<Result> disconnectCiCam() override;
 
     // Functions interacts with Tuner Service
-    void stopBroadcastInput();
+    void stopFrontendInput();
     Result removeFilter(uint32_t filterId);
+    bool attachRecordFilter(int filterId);
+    bool detachRecordFilter(int filterId);
     Result startFilterHandler(uint32_t filterId);
     void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
     uint16_t getFilterTpid(uint32_t filterId);
+    void setIsRecording(bool isRecording);
 
   private:
     // Tuner service
@@ -101,9 +104,9 @@
         uint32_t filterId;
     };
 
-    Result startBroadcastInputLoop();
-    static void* __threadLoopBroadcast(void* user);
-    void broadcastInputThreadLoop();
+    Result startFrontendInputLoop();
+    static void* __threadLoopFrontend(void* user);
+    void frontendInputThreadLoop();
 
     /**
      * To create a FilterMQ with the the next available Filter ID.
@@ -117,9 +120,13 @@
     /**
      * A dispatcher to read and dispatch input data to all the started filters.
      * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     * Note that recording filters are not included.
      */
-    bool startFilterDispatcher();
-    void startTsFilter(vector<uint8_t> data);
+    bool startBroadcastFilterDispatcher();
+    void startBroadcastTsFilter(vector<uint8_t> data);
+
+    void sendFrontendInputToRecord(vector<uint8_t> data);
+    bool startRecordFilterDispatcher();
 
     uint32_t mDemuxId;
     uint32_t mCiCamId;
@@ -141,26 +148,40 @@
      */
     set<uint32_t> mUnusedFilterIds;
     /**
+     * Record all the attached record filter Ids.
+     * Any removed filter id should be removed from this set.
+     */
+    set<uint32_t> mRecordFilterIds;
+    /**
      * A list of created FilterMQ ptrs.
      * The array number is the filter ID.
      */
     std::map<uint32_t, sp<Filter>> mFilters;
 
+    /**
+     * Local reference to the opened DVR object.
+     */
+    sp<Dvr> mDvr;
+
     // Thread handlers
-    pthread_t mBroadcastInputThread;
+    pthread_t mFrontendInputThread;
     /**
      * If a specific filter's writing loop is still running
      */
-    bool mBroadcastInputThreadRunning;
+    bool mFrontendInputThreadRunning;
     bool mKeepFetchingDataFromFrontend;
     /**
+     * If the dvr recording is running.
+     */
+    bool mIsRecording = false;
+    /**
      * Lock to protect writes to the FMQs
      */
     std::mutex mWriteLock;
     /**
      * Lock to protect writes to the input status
      */
-    std::mutex mBroadcastInputThreadLock;
+    std::mutex mFrontendInputThreadLock;
 
     // temp handle single PES filter
     // TODO handle mulptiple Pes filters
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
index eb38f90..3088a9d 100644
--- a/tv/tuner/1.0/default/Dvr.cpp
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -70,7 +70,14 @@
         return status;
     }
 
+    // check if the attached filter is a record filter
+
     mFilters[filterId] = filter;
+    mIsRecordFilterAttached = true;
+    if (!mDemux->attachRecordFilter(filterId)) {
+        return Result::INVALID_ARGUMENT;
+    }
+    mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
 
     return Result::SUCCESS;
 }
@@ -95,6 +102,15 @@
     it = mFilters.find(filterId);
     if (it != mFilters.end()) {
         mFilters.erase(filterId);
+        if (!mDemux->detachRecordFilter(filterId)) {
+            return Result::INVALID_ARGUMENT;
+        }
+    }
+
+    // If all the filters are detached, record can't be started
+    if (mFilters.empty()) {
+        mIsRecordFilterAttached = false;
+        mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
     }
 
     return Result::SUCCESS;
@@ -115,8 +131,9 @@
         pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
         pthread_setname_np(mDvrThread, "playback_waiting_loop");
     } else if (mType == DvrType::RECORD) {
-        /*pthread_create(&mInputThread, NULL, __threadLoopInput, this);
-        pthread_setname_np(mInputThread, "playback_waiting_loop");*/
+        mRecordStatus = RecordStatus::DATA_READY;
+        mIsRecordStarted = true;
+        mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
     }
 
     // TODO start another thread to send filter status callback to the framework
@@ -131,12 +148,17 @@
 
     std::lock_guard<std::mutex> lock(mDvrThreadLock);
 
+    mIsRecordStarted = false;
+    mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
+
     return Result::SUCCESS;
 }
 
 Return<Result> Dvr::flush() {
     ALOGV("%s", __FUNCTION__);
 
+    mRecordStatus = RecordStatus::DATA_READY;
+
     return Result::SUCCESS;
 }
 
@@ -272,6 +294,45 @@
     return true;
 }
 
+bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
+    std::lock_guard<std::mutex> lock(mWriteLock);
+    ALOGW("[Dvr] write record FMQ");
+    if (mDvrMQ->write(data.data(), data.size())) {
+        mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+        maySendRecordStatusCallback();
+        return true;
+    }
+
+    maySendRecordStatusCallback();
+    return false;
+}
+
+void Dvr::maySendRecordStatusCallback() {
+    std::lock_guard<std::mutex> lock(mRecordStatusLock);
+    int availableToRead = mDvrMQ->availableToRead();
+    int availableToWrite = mDvrMQ->availableToWrite();
+
+    RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
+                                                     mDvrSettings.record().highThreshold,
+                                                     mDvrSettings.record().lowThreshold);
+    if (mRecordStatus != newStatus) {
+        mCallback->onRecordStatus(newStatus);
+        mRecordStatus = newStatus;
+    }
+}
+
+RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                          uint32_t highThreshold, uint32_t lowThreshold) {
+    if (availableToWrite == 0) {
+        return DemuxFilterStatus::OVERFLOW;
+    } else if (availableToRead > highThreshold) {
+        return DemuxFilterStatus::HIGH_WATER;
+    } else if (availableToRead < lowThreshold) {
+        return DemuxFilterStatus::LOW_WATER;
+    }
+    return mRecordStatus;
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
index fbb778c..f39d8db 100644
--- a/tv/tuner/1.0/default/Dvr.h
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -79,6 +79,8 @@
      * Return false is any of the above processes fails.
      */
     bool createDvrMQ();
+    void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer);
+    bool writeRecordFMQ(const std::vector<uint8_t>& data);
 
   private:
     // Demux service
@@ -95,6 +97,8 @@
     void maySendRecordStatusCallback();
     PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
                                              uint32_t highThreshold, uint32_t lowThreshold);
+    RecordStatus checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                         uint32_t highThreshold, uint32_t lowThreshold);
     /**
      * A dispatcher to read and dispatch input data to all the started filters.
      * Each filter handler handles the data filtering/output writing/filterEvent updating.
@@ -103,9 +107,9 @@
     void startTpidFilter(vector<uint8_t> data);
     bool startFilterDispatcher();
     static void* __threadLoopPlayback(void* user);
-    static void* __threadLoopBroadcast(void* user);
+    static void* __threadLoopRecord(void* user);
     void playbackThreadLoop();
-    void broadcastInputThreadLoop();
+    void recordThreadLoop();
 
     unique_ptr<DvrMQ> mDvrMQ;
     EventFlag* mDvrEventFlag;
@@ -121,6 +125,7 @@
 
     // FMQ status local records
     PlaybackStatus mPlaybackStatus;
+    RecordStatus mRecordStatus;
     /**
      * If a specific filter's writing loop is still running
      */
@@ -135,10 +140,16 @@
      * Lock to protect writes to the input status
      */
     std::mutex mPlaybackStatusLock;
+    std::mutex mRecordStatusLock;
     std::mutex mBroadcastInputThreadLock;
     std::mutex mDvrThreadLock;
 
     const bool DEBUG_DVR = false;
+
+    // Booleans to check if recording is running.
+    // Recording is ready when both of the following are set to true.
+    bool mIsRecordStarted = false;
+    bool mIsRecordFilterAttached = false;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
index befd1e6..b3160fc 100644
--- a/tv/tuner/1.0/default/Filter.cpp
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -265,10 +265,16 @@
 
 void Filter::updateFilterOutput(vector<uint8_t> data) {
     std::lock_guard<std::mutex> lock(mFilterOutputLock);
-    ALOGD("[Filter] handler output updated");
+    ALOGD("[Filter] filter output updated");
     mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
 }
 
+void Filter::updateRecordOutput(vector<uint8_t> data) {
+    std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+    ALOGD("[Filter] record filter output updated");
+    mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end());
+}
+
 Result Filter::startFilterHandler() {
     std::lock_guard<std::mutex> lock(mFilterOutputLock);
     switch (mType.mainType) {
@@ -292,12 +298,11 @@
                 case DemuxTsFilterType::PCR:
                     startPcrFilterHandler();
                     break;
-                case DemuxTsFilterType::RECORD:
-                    startRecordFilterHandler();
-                    break;
                 case DemuxTsFilterType::TEMI:
                     startTemiFilterHandler();
                     break;
+                default:
+                    break;
             }
             break;
         case DemuxFilterMainType::MMTP:
@@ -342,12 +347,16 @@
         if (mPesSizeLeft == 0) {
             uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
                               mFilterOutput[i + 6];
-            ALOGD("[Filter] prefix %d", prefix);
+            if (DEBUG_FILTER) {
+                ALOGD("[Filter] prefix %d", prefix);
+            }
             if (prefix == 0x000001) {
                 // TODO handle mulptiple Pes filters
                 mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
                 mPesSizeLeft += 6;
-                ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+                if (DEBUG_FILTER) {
+                    ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+                }
             } else {
                 continue;
             }
@@ -360,7 +369,9 @@
         mPesOutput.insert(mPesOutput.end(), first, last);
         // size does not match then continue
         mPesSizeLeft -= endPoint;
-        ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+        if (DEBUG_FILTER) {
+            ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+        }
         if (mPesSizeLeft > 0) {
             continue;
         }
@@ -377,7 +388,9 @@
                 .streamId = mPesOutput[3],
                 .dataLength = static_cast<uint16_t>(mPesOutput.size()),
         };
-        ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+        if (DEBUG_FILTER) {
+            ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+        }
 
         int size = mFilterEvent.events.size();
         mFilterEvent.events.resize(size + 1);
@@ -413,13 +426,23 @@
 }
 
 Result Filter::startRecordFilterHandler() {
-    DemuxFilterTsRecordEvent tsRecordEvent;
+    /*DemuxFilterTsRecordEvent tsRecordEvent;
     tsRecordEvent.pid.tPid(0);
     tsRecordEvent.indexMask.tsIndexMask(0x01);
     mFilterEvent.events.resize(1);
     mFilterEvent.events[0].tsRecord(tsRecordEvent);
+*/
+    std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+    if (mRecordFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
 
-    mFilterOutput.clear();
+    if (mDvr == nullptr || !mDvr->writeRecordFMQ(mRecordFilterOutput)) {
+        ALOGD("[Filter] dvr fails to write into record FMQ.");
+        return Result::UNKNOWN_ERROR;
+    }
+
+    mRecordFilterOutput.clear();
     return Result::SUCCESS;
 }
 
@@ -462,6 +485,14 @@
     return false;
 }
 
+void Filter::attachFilterToRecord(const sp<Dvr> dvr) {
+    mDvr = dvr;
+}
+
+void Filter::detachFilterFromRecord() {
+    mDvr = nullptr;
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
index fbd965a..d397f73 100644
--- a/tv/tuner/1.0/default/Filter.h
+++ b/tv/tuner/1.0/default/Filter.h
@@ -22,6 +22,7 @@
 #include <math.h>
 #include <set>
 #include "Demux.h"
+#include "Dvr.h"
 #include "Frontend.h"
 
 using namespace std;
@@ -44,6 +45,7 @@
 using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
 
 class Demux;
+class Dvr;
 
 class Filter : public IFilter {
   public:
@@ -80,11 +82,17 @@
     bool createFilterMQ();
     uint16_t getTpid();
     void updateFilterOutput(vector<uint8_t> data);
+    void updateRecordOutput(vector<uint8_t> data);
     Result startFilterHandler();
+    Result startRecordFilterHandler();
+    void attachFilterToRecord(const sp<Dvr> dvr);
+    void detachFilterFromRecord();
 
   private:
     // Tuner service
     sp<Demux> mDemux;
+    // Dvr reference once the filter is attached to any
+    sp<Dvr> mDvr = nullptr;
     /**
      * Filter callbacks used on filter events or FMQ status
      */
@@ -99,6 +107,7 @@
     sp<IFilter> mDataSource;
     bool mIsDataSourceDemux = true;
     vector<uint8_t> mFilterOutput;
+    vector<uint8_t> mRecordFilterOutput;
     unique_ptr<FilterMQ> mFilterMQ;
     EventFlag* mFilterEventFlag;
     DemuxFilterEvent mFilterEvent;
@@ -120,6 +129,8 @@
      */
     const uint16_t SECTION_WRITE_COUNT = 10;
 
+    bool DEBUG_FILTER = false;
+
     /**
      * Filter handlers to handle the data filtering.
      * They are also responsible to write the filtered output into the filter FMQ
@@ -129,7 +140,6 @@
     Result startPesFilterHandler();
     Result startTsFilterHandler();
     Result startMediaFilterHandler();
-    Result startRecordFilterHandler();
     Result startPcrFilterHandler();
     Result startTemiFilterHandler();
     Result startFilterLoop();
@@ -165,6 +175,7 @@
     std::mutex mFilterStatusLock;
     std::mutex mFilterThreadLock;
     std::mutex mFilterOutputLock;
+    std::mutex mRecordFilterOutputLock;
 
     // temp handle single PES filter
     // TODO handle mulptiple Pes filters
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index f86b28d..c143d61 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -148,7 +148,7 @@
     uint32_t demuxId;
     if (it != mFrontendToDemux.end()) {
         demuxId = it->second;
-        mDemuxes[demuxId]->stopBroadcastInput();
+        mDemuxes[demuxId]->stopFrontendInput();
     }
 }
 
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 707f5df..1dea04e 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -2230,8 +2230,6 @@
 
         DemuxFilterSectionSettings section;
 
-        DemuxFilterPesDataSettings pesData;
-
         /**
          * true if the data from IP subtype go to next filter directly
          */
@@ -2248,7 +2246,7 @@
     /**
      * true if the filtered data is commpressed ip packet
      */
-    bool bIsCompressedIpPacket;
+    bool isCompressedIpPacket;
 
     safe_union FilterSettings {
         /**
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index da3e300..7977f25 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -65,6 +65,7 @@
 using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
 using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
 using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
@@ -95,6 +96,7 @@
 using android::hardware::tv::tuner::V1_0::ITuner;
 using android::hardware::tv::tuner::V1_0::PlaybackSettings;
 using android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
 using android::hardware::tv::tuner::V1_0::RecordStatus;
 using android::hardware::tv::tuner::V1_0::Result;
 
@@ -379,7 +381,20 @@
 
 class DvrCallback : public IDvrCallback {
   public:
-    virtual Return<void> onRecordStatus(RecordStatus /*status*/) override { return Void(); }
+    virtual Return<void> onRecordStatus(DemuxFilterStatus status) override {
+        ALOGW("[vts] record status %hhu", status);
+        switch (status) {
+            case DemuxFilterStatus::DATA_READY:
+                break;
+            case DemuxFilterStatus::LOW_WATER:
+                break;
+            case DemuxFilterStatus::HIGH_WATER:
+            case DemuxFilterStatus::OVERFLOW:
+                ALOGW("[vts] record overflow. Flushing");
+                break;
+        }
+        return Void();
+    }
 
     virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
         // android::Mutex::Autolock autoLock(mMsgLock);
@@ -401,10 +416,17 @@
 
     void testFilterDataOutput();
     void stopPlaybackThread();
+    void testRecordOutput();
+    void stopRecordThread();
 
     void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor);
+    void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor);
     static void* __threadLoopPlayback(void* threadArgs);
+    static void* __threadLoopRecord(void* threadArgs);
     void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ);
+    void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ);
+
+    bool readRecordFMQ();
 
   private:
     struct PlaybackThreadArgs {
@@ -412,22 +434,31 @@
         PlaybackConf* playbackConf;
         bool* keepWritingPlaybackFMQ;
     };
+    struct RecordThreadArgs {
+        DvrCallback* user;
+        RecordSettings* recordSetting;
+        bool* keepReadingRecordFMQ;
+    };
     uint16_t mDataLength = 0;
     std::vector<uint8_t> mDataOutputBuffer;
 
     std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
     std::unique_ptr<FilterMQ> mPlaybackMQ;
+    std::unique_ptr<FilterMQ> mRecordMQ;
     std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
     std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
-    EventFlag* mPlaybackMQEventFlag;
 
     android::Mutex mMsgLock;
     android::Mutex mPlaybackThreadLock;
+    android::Mutex mRecordThreadLock;
     android::Condition mMsgCondition;
 
     bool mKeepWritingPlaybackFMQ = true;
+    bool mKeepReadingRecordFMQ = true;
     bool mPlaybackThreadRunning;
+    bool mRecordThreadRunning;
     pthread_t mPlaybackThread;
+    pthread_t mRecordThread;
 
     int mPidFilterOutputCount = 0;
 };
@@ -516,6 +547,92 @@
     inputData.close();
 }
 
+void DvrCallback::testRecordOutput() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (mDataOutputBuffer.empty()) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
+            return;
+        }
+    }
+    stopRecordThread();
+    ALOGW("[vts] record pass and stop");
+}
+
+void DvrCallback::startRecordOutputThread(RecordSettings recordSetting,
+                                          MQDesc& recordMQDescriptor) {
+    mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mRecordMQ);
+    struct RecordThreadArgs* threadArgs =
+            (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs));
+    threadArgs->user = this;
+    threadArgs->recordSetting = &recordSetting;
+    threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ;
+
+    pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs);
+    pthread_setname_np(mRecordThread, "test_record_input_loop");
+}
+
+void* DvrCallback::__threadLoopRecord(void* threadArgs) {
+    DvrCallback* const self =
+            static_cast<DvrCallback*>(((struct RecordThreadArgs*)threadArgs)->user);
+    self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSetting,
+                           ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ);
+    return 0;
+}
+
+void DvrCallback::recordThreadLoop(RecordSettings* /*recordSetting*/, bool* keepReadingRecordFMQ) {
+    ALOGD("[vts] DvrCallback record threadLoop start.");
+    android::Mutex::Autolock autoLock(mRecordThreadLock);
+    mRecordThreadRunning = true;
+
+    // Create the EventFlag that is used to signal the HAL impl that data have been
+    // read from the Record FMQ
+    EventFlag* recordMQEventFlag;
+    EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
+                android::OK);
+
+    while (mRecordThreadRunning) {
+        while (*keepReadingRecordFMQ) {
+            uint32_t efState = 0;
+            android::status_t status = recordMQEventFlag->wait(
+                    static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+                    true /* retry on spurious wake */);
+            if (status != android::OK) {
+                ALOGD("[vts] wait for data ready on the record FMQ");
+                continue;
+            }
+            // Our current implementation filter the data and write it into the filter FMQ
+            // immediately after the DATA_READY from the VTS/framework
+            if (!readRecordFMQ()) {
+                ALOGD("[vts] record data failed to be filtered. Ending thread");
+                mRecordThreadRunning = false;
+                break;
+            }
+        }
+    }
+
+    mRecordThreadRunning = false;
+    ALOGD("[vts] record thread ended.");
+}
+
+bool DvrCallback::readRecordFMQ() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    bool result = false;
+    mDataOutputBuffer.clear();
+    mDataOutputBuffer.resize(mRecordMQ->availableToRead());
+    result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
+    EXPECT_TRUE(result) << "can't read from Record MQ";
+    mMsgCondition.signal();
+    return result;
+}
+
+void DvrCallback::stopRecordThread() {
+    mKeepReadingRecordFMQ = false;
+    mRecordThreadRunning = false;
+    android::Mutex::Autolock autoLock(mRecordThreadLock);
+}
+
 // Test environment for Tuner HIDL HAL.
 class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
   public:
@@ -555,6 +672,7 @@
     sp<DvrCallback> mDvrCallback;
     MQDesc mFilterMQDescriptor;
     MQDesc mPlaybackMQDescriptor;
+    MQDesc mRecordMQDescriptor;
     vector<uint32_t> mUsedFilterIds;
 
     uint32_t mDemuxId;
@@ -572,6 +690,8 @@
                                                        FrontendSettings settings);
     ::testing::AssertionResult getPlaybackMQDescriptor();
     ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting);
+    ::testing::AssertionResult getRecordMQDescriptor();
+    ::testing::AssertionResult addRecordToDemux(RecordSettings setting);
     ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting);
     ::testing::AssertionResult getFilterMQDescriptor();
     ::testing::AssertionResult closeDemux();
@@ -581,6 +701,9 @@
     ::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
                                                     PlaybackConf playbackConf,
                                                     vector<string> goldenOutputFiles);
+    ::testing::AssertionResult recordDataFlowTest(vector<FilterConf> filterConf,
+                                                  RecordSettings recordSetting,
+                                                  vector<string> goldenOutputFiles);
     ::testing::AssertionResult broadcastDataFlowTest(vector<FilterConf> filterConf,
                                                      vector<string> goldenOutputFiles);
 };
@@ -766,6 +889,49 @@
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
+::testing::AssertionResult TunerHidlTest::addRecordToDemux(RecordSettings setting) {
+    Result status;
+
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Create dvr callback
+    mDvrCallback = new DvrCallback();
+
+    // Add playback input to the local demux
+    mDemux->openDvr(DvrType::RECORD, FMQ_SIZE_1M, mDvrCallback,
+                    [&](Result result, const sp<IDvr>& dvr) {
+                        mDvr = dvr;
+                        status = result;
+                    });
+
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    DvrSettings dvrSetting;
+    dvrSetting.record(setting);
+    status = mDvr->configure(dvrSetting);
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::getRecordMQDescriptor() {
+    Result status;
+
+    if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) {
+        return ::testing::AssertionFailure();
+    }
+
+    mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+        mRecordMQDescriptor = dvrMQDesc;
+        status = result;
+    });
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
 ::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type,
                                                            DemuxFilterSettings setting) {
     Result status;
@@ -997,6 +1163,82 @@
     return closeDemux();
 }
 
+::testing::AssertionResult TunerHidlTest::recordDataFlowTest(vector<FilterConf> filterConf,
+                                                             RecordSettings recordSetting,
+                                                             vector<string> /*goldenOutputFiles*/) {
+    Result status;
+    hidl_vec<FrontendId> feIds;
+
+    mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+        status = result;
+        feIds = frontendIds;
+    });
+
+    if (feIds.size() == 0) {
+        ALOGW("[   WARN   ] Frontend isn't available");
+        return ::testing::AssertionFailure();
+    }
+
+    FrontendDvbtSettings dvbt{
+            .frequency = 1000,
+    };
+    FrontendSettings settings;
+    settings.dvbt(dvbt);
+
+    int filterIdsSize;
+    // Filter Configuration Module
+    for (int i = 0; i < filterConf.size(); i++) {
+        if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
+                    ::testing::AssertionFailure() ||
+            // TODO use a map to save the FMQs/EvenFlags and pass to callback
+            getFilterMQDescriptor() == ::testing::AssertionFailure()) {
+            return ::testing::AssertionFailure();
+        }
+        filterIdsSize = mUsedFilterIds.size();
+        mUsedFilterIds.resize(filterIdsSize + 1);
+        mUsedFilterIds[filterIdsSize] = mFilterId;
+        mFilters[mFilterId] = mFilter;
+    }
+
+    // Record Config Module
+    if (addRecordToDemux(recordSetting) == ::testing::AssertionFailure() ||
+        getRecordMQDescriptor() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+
+    mDvrCallback->startRecordOutputThread(recordSetting, mRecordMQDescriptor);
+    status = mDvr->start();
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Data Verify Module
+    mDvrCallback->testRecordOutput();
+
+    // Clean Up Module
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+    if (mFrontend->stopTune() != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+    mUsedFilterIds.clear();
+    mFilterCallbacks.clear();
+    mFilters.clear();
+    return closeDemux();
+}
+
 /*
  * API STATUS TESTS
  */
@@ -1203,6 +1445,44 @@
     ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles));
 }
 
+TEST_F(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
+    description("Feed ts data from frontend to recording and test with ts record filter");
+
+    // todo modulize the filter conf parser
+    vector<FilterConf> filterConf;
+    filterConf.resize(1);
+
+    DemuxFilterSettings filterSetting;
+    DemuxTsFilterSettings tsFilterSetting{
+            .tpid = 119,
+    };
+    DemuxFilterRecordSettings recordFilterSetting;
+    tsFilterSetting.filterSettings.record(recordFilterSetting);
+    filterSetting.ts(tsFilterSetting);
+
+    DemuxFilterType type{
+            .mainType = DemuxFilterMainType::TS,
+    };
+    type.subType.tsFilterType(DemuxTsFilterType::RECORD);
+    FilterConf recordFilterConf{
+            .type = type,
+            .setting = filterSetting,
+    };
+    filterConf[0] = recordFilterConf;
+
+    RecordSettings recordSetting{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x07fff,
+            .dataFormat = DataFormat::TS,
+            .packetSize = 188,
+    };
+
+    vector<string> goldenOutputFiles;
+
+    ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles));
+}
+
 }  // namespace
 
 int main(int argc, char** argv) {
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index f47b10d..0e2b3e1 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -34,18 +34,10 @@
 using android::hardware::vibrator::EffectStrength;
 using android::hardware::vibrator::IVibrator;
 
-// TODO(b/143992652): autogenerate
-const std::vector<Effect> kEffects = {
-        Effect::CLICK,       Effect::DOUBLE_CLICK, Effect::TICK,        Effect::THUD,
-        Effect::POP,         Effect::HEAVY_CLICK,  Effect::RINGTONE_1,  Effect::RINGTONE_2,
-        Effect::RINGTONE_3,  Effect::RINGTONE_4,   Effect::RINGTONE_5,  Effect::RINGTONE_6,
-        Effect::RINGTONE_7,  Effect::RINGTONE_8,   Effect::RINGTONE_9,  Effect::RINGTONE_10,
-        Effect::RINGTONE_11, Effect::RINGTONE_12,  Effect::RINGTONE_13, Effect::RINGTONE_14,
-        Effect::RINGTONE_15, Effect::TEXTURE_TICK};
-
-// TODO(b/143992652): autogenerate
-const std::vector<EffectStrength> kEffectStrengths = {EffectStrength::LIGHT, EffectStrength::MEDIUM,
-                                                      EffectStrength::STRONG};
+const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
+                                   android::enum_range<Effect>().end()};
+const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
+                                                   android::enum_range<EffectStrength>().end()};
 
 const std::vector<Effect> kInvalidEffects = {
         static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
diff --git a/wifi/hostapd/1.2/IHostapd.hal b/wifi/hostapd/1.2/IHostapd.hal
index 31ade13..1bac1e7 100644
--- a/wifi/hostapd/1.2/IHostapd.hal
+++ b/wifi/hostapd/1.2/IHostapd.hal
@@ -16,6 +16,7 @@
 
 package android.hardware.wifi.hostapd@1.2;
 
+import @1.0::IHostapd.NetworkParams;
 import @1.1::IHostapd;
 import HostapdStatus;
 import MacAddress;
@@ -26,6 +27,86 @@
  */
 interface IHostapd extends @1.1::IHostapd {
     /**
+     * Band bitmMask to use for the SoftAp operations.
+     * A combinatoin of these bits are used to identify the allowed bands
+     * to start the softAp
+     */
+    enum BandMask : uint32_t {
+        /**
+         * 2.4 GHz band.
+         */
+        BAND_2_GHZ = 1 << 0,
+        /**
+         * 5 GHz band.
+         */
+        BAND_5_GHZ = 1 << 1,
+        /**
+         * 6 GHz band.
+         */
+        BAND_6_GHZ = 1 << 2,
+    };
+
+    /**
+     * Parameters to control the HW mode for the interface.
+     */
+    struct HwModeParams {
+        /**
+         * Whether IEEE 802.11ax (HE) is enabled or not.
+         * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
+         * used with HE.
+         */
+        bool enable80211AX;
+        /**
+         * Whether 6GHz band enabled or not on softAp.
+         * Note: hw_mode=a is used to specify that 5 GHz band or 6 GHz band is
+         * used.
+         */
+        bool enable6GhzBand;
+    };
+
+    /**
+     * Parameters to control the channel selection for the interface.
+     */
+    struct ChannelParams {
+        /**
+         * Band to use for the SoftAp operations.
+         */
+        bitfield<BandMask> bandMask;
+    };
+
+    /**
+     * Parameters to use for setting up the access point interface.
+     */
+    struct IfaceParams {
+        /**
+         * Baseline information as defined in HAL 1.1.
+         */
+        @1.1::IHostapd.IfaceParams V1_1;
+        /** Additional Hw mode params for the interface */
+        HwModeParams hwModeParams;
+        /** Additional Channel params for the interface */
+        ChannelParams channelParams;
+    };
+
+    /**
+     * Adds a new access point for hostapd to control.
+     *
+     * This should trigger the setup of an access point with the specified
+     * interface and network params.
+     *
+     * @param ifaceParams AccessPoint Params for the access point.
+     * @param nwParams Network Params for the access point.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |HostapdStatusCode.SUCCESS|,
+     *         |HostapdStatusCode.FAILURE_ARGS_INVALID|,
+     *         |HostapdStatusCode.FAILURE_UNKNOWN|,
+     *         |HostapdStatusCode.FAILURE_IFACE_EXISTS|
+     */
+    addAccessPoint_1_2(IfaceParams ifaceParams, NetworkParams nwParams)
+        generates(HostapdStatus status);
+
+    /**
      * force one of the hotspot clients disconnect..
      *
      * @param ifaceName Name of the interface.
diff --git a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
index 0d37221..b092d00 100644
--- a/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.2/vts/functional/hostapd_hidl_test.cpp
@@ -39,7 +39,9 @@
 namespace {
 constexpr unsigned char kNwSsid[] = {'t', 'e', 's', 't', '1',
                                      '2', '3', '4', '5'};
+constexpr char kNwPassphrase[] = "test12345";
 constexpr int kIfaceChannel = 6;
+constexpr int kIfaceInvalidChannel = 567;
 constexpr uint8_t kTestZeroMacAddr[] = {[0 ... 5] = 0x0};
 constexpr Ieee80211ReasonCode kTestDisconnectReasonCode =
     Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED;
@@ -73,7 +75,9 @@
     IHostapd::IfaceParams getIfaceParamsWithoutAcs() {
         ::android::hardware::wifi::hostapd::V1_0::IHostapd::IfaceParams
             iface_params;
-        IHostapd::IfaceParams iface_params_1_1;
+        ::android::hardware::wifi::hostapd::V1_1::IHostapd::IfaceParams
+            iface_params_1_1;
+        IHostapd::IfaceParams iface_params_1_2;
 
         iface_params.ifaceName = getPrimaryWlanIfaceName();
         iface_params.hwModeParams.enable80211N = true;
@@ -81,9 +85,52 @@
         iface_params.channelParams.enableAcs = false;
         iface_params.channelParams.acsShouldExcludeDfs = false;
         iface_params.channelParams.channel = kIfaceChannel;
-        iface_params.channelParams.band = IHostapd::Band::BAND_2_4_GHZ;
         iface_params_1_1.V1_0 = iface_params;
-        return iface_params_1_1;
+        iface_params_1_2.V1_1 = iface_params_1_1;
+        // Newly added attributes in V1_2
+        iface_params_1_2.hwModeParams.enable80211AX = false;
+        iface_params_1_2.hwModeParams.enable6GhzBand = false;
+        iface_params_1_2.channelParams.bandMask = 0;
+        iface_params_1_2.channelParams.bandMask |=
+            IHostapd::BandMask::BAND_2_GHZ;
+        return iface_params_1_2;
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithAcs() {
+        // First get the settings for WithoutAcs and then make changes
+        IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+        iface_params_1_2.V1_1.V1_0.channelParams.enableAcs = true;
+        iface_params_1_2.V1_1.V1_0.channelParams.acsShouldExcludeDfs = true;
+        iface_params_1_2.V1_1.V1_0.channelParams.channel = 0;
+        iface_params_1_2.channelParams.bandMask |=
+            IHostapd::BandMask::BAND_5_GHZ;
+
+        return iface_params_1_2;
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithAcsAndChannelRange() {
+        IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithAcs();
+        ::android::hardware::wifi::hostapd::V1_1::IHostapd::ChannelParams
+            channelParams;
+        ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange
+            acsChannelRange;
+        acsChannelRange.start = 1;
+        acsChannelRange.end = 11;
+        std::vector<
+            ::android::hardware::wifi::hostapd::V1_1::IHostapd::AcsChannelRange>
+            vec_acsChannelRange;
+        vec_acsChannelRange.push_back(acsChannelRange);
+        channelParams.acsChannelRanges = vec_acsChannelRange;
+        iface_params_1_2.V1_1.channelParams = channelParams;
+        return iface_params_1_2;
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithAcsAndInvalidChannelRange() {
+        IHostapd::IfaceParams iface_params_1_2 =
+            getIfaceParamsWithAcsAndChannelRange();
+        iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].start = 222;
+        iface_params_1_2.V1_1.channelParams.acsChannelRanges[0].end = 999;
+        return iface_params_1_2;
     }
 
     IHostapd::NetworkParams getOpenNwParams() {
@@ -95,6 +142,31 @@
         return nw_params;
     }
 
+    IHostapd::NetworkParams getPskNwParams() {
+        IHostapd::NetworkParams nw_params;
+        nw_params.ssid =
+            std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+        nw_params.isHidden = false;
+        nw_params.encryptionType = IHostapd::EncryptionType::WPA2;
+        nw_params.pskPassphrase = kNwPassphrase;
+        return nw_params;
+    }
+
+    IHostapd::NetworkParams getInvalidPskNwParams() {
+        IHostapd::NetworkParams nw_params;
+        nw_params.ssid =
+            std::vector<uint8_t>(kNwSsid, kNwSsid + sizeof(kNwSsid));
+        nw_params.isHidden = false;
+        nw_params.encryptionType = IHostapd::EncryptionType::WPA2;
+        return nw_params;
+    }
+
+    IHostapd::IfaceParams getIfaceParamsWithInvalidChannel() {
+        IHostapd::IfaceParams iface_params_1_2 = getIfaceParamsWithoutAcs();
+        iface_params_1_2.V1_1.V1_0.channelParams.channel = kIfaceInvalidChannel;
+        return iface_params_1_2;
+    }
+
     // IHostapd object used for all tests in this fixture.
     sp<IHostapd> hostapd_;
     std::string wifi_instance_name_;
@@ -102,6 +174,125 @@
 };
 
 /**
+ * Adds an access point with PSK network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithAcs(), getPskNwParams());
+    // TODO: b/140172237, fix this in R.
+    // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config, ACS enabled & channel Range.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndChannelRange) {
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithAcsAndChannelRange(), getPskNwParams());
+    // TODO: b/140172237, fix this in R
+    // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid channel range.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithAcsAndInvalidChannelRange) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithAcsAndInvalidChannelRange(),
+                              getPskNwParams());
+    // TODO: b/140172237, fix this in R
+    // EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS enabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithAcs(), getOpenNwParams());
+    // TODO: b/140172237, fix this in R
+    // EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with PSK network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithoutAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithoutAcs(), getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with Open network config & ACS disabled.
+ * Access point creation should pass.
+ */
+TEST_P(HostapdHidlTest, AddOpenAccessPointWithoutAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithoutAcs(), getOpenNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS enabled.
+ * Access point creation & removal should pass.
+ */
+TEST_P(HostapdHidlTest, RemoveAccessPointWithAcs) {
+    auto status = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                              getIfaceParamsWithAcs(), getPskNwParams());
+    // TODO: b/140172237, fix this in R
+    /*
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    status =
+        HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status.code);
+    */
+}
+
+/**
+ * Adds & then removes an access point with PSK network config & ACS disabled.
+ * Access point creation & removal should pass.
+ */
+TEST_P(HostapdHidlTest, RemoveAccessPointWithoutAcs) {
+    auto status_1_2 = HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                                  getIfaceParamsWithoutAcs(), getPskNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+    auto status =
+        HIDL_INVOKE(hostapd_, removeAccessPoint, getPrimaryWlanIfaceName());
+    EXPECT_EQ(
+        android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
+        status.code);
+}
+
+/**
+ * Adds an access point with invalid channel.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddPskAccessPointWithInvalidChannel) {
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2,
+                    getIfaceParamsWithInvalidChannel(), getPskNwParams());
+    EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
+ * Adds an access point with invalid PSK network config.
+ * Access point creation should fail.
+ */
+TEST_P(HostapdHidlTest, AddInvalidPskAccessPointWithoutAcs) {
+    auto status =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+                    getInvalidPskNwParams());
+    EXPECT_NE(HostapdStatusCode::SUCCESS, status.code);
+}
+
+/**
  * forceClientDisconnect should return FAILURE_IFACE_UNKNOWN
  * when hotspot interface doesn't init..
  */
@@ -117,14 +308,12 @@
  * when hotspot interface available.
  */
 TEST_P(HostapdHidlTest, DisconnectClientWhenIfacAvailable) {
-    auto status_1_0 =
-        HIDL_INVOKE(hostapd_, addAccessPoint_1_1, getIfaceParamsWithoutAcs(),
-                    getOpenNwParams());
-    EXPECT_EQ(
-        android::hardware::wifi::hostapd::V1_0::HostapdStatusCode::SUCCESS,
-        status_1_0.code);
-
     auto status_1_2 =
+        HIDL_INVOKE(hostapd_, addAccessPoint_1_2, getIfaceParamsWithoutAcs(),
+                    getOpenNwParams());
+    EXPECT_EQ(HostapdStatusCode::SUCCESS, status_1_2.code);
+
+    status_1_2 =
         HIDL_INVOKE(hostapd_, forceClientDisconnect, getPrimaryWlanIfaceName(),
                     kTestZeroMacAddr, kTestDisconnectReasonCode);
     EXPECT_EQ(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN, status_1_2.code);
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index 15525bb..332ee4a 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -19,7 +19,7 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["supplicant_hidl_test_utils.cpp"],
     export_include_dirs: [
-        "."
+        ".",
     ],
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
@@ -51,14 +51,17 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
 
 cc_test {
     name: "VtsHalWifiSupplicantP2pV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "VtsHalWifiSupplicantV1_0TargetTest.cpp",
+        "VtsHalWifiSupplicantP2pV1_0TargetTest.cpp",
         "supplicant_p2p_iface_hidl_test.cpp",
     ],
     static_libs: [
@@ -71,5 +74,8 @@
         "libwifi-system",
         "libwifi-system-iface",
     ],
-    test_suites: ["general-tests", "vts-core"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
new file mode 100644
index 0000000..a132707
--- /dev/null
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsCoreUtil.h>
+#include "supplicant_hidl_test_utils.h"
+
+// TODO(b/143892896): Remove this line after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
+
+int main(int argc, char** argv) {
+    if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct"))
+        return 0;
+
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/wifi/supplicant/1.3/ISupplicantStaIface.hal b/wifi/supplicant/1.3/ISupplicantStaIface.hal
index bfd8946..fa88b91 100644
--- a/wifi/supplicant/1.3/ISupplicantStaIface.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaIface.hal
@@ -18,6 +18,7 @@
 
 import @1.0::SupplicantStatus;
 import @1.2::ISupplicantStaIface;
+import @1.3::ISupplicantStaNetwork;
 import ISupplicantStaIfaceCallback;
 
 /**
@@ -76,4 +77,17 @@
      *         |SupplicantStatusCode.FAILURE_UNKNOWN|
      */
     setMboCellularDataStatus(bool available) generates (SupplicantStatus status);
+
+    /**
+     * Get Key management capabilities of the device
+     *
+     * @return status Status of the operation, and a bitmap of key management mask.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    getKeyMgmtCapabilities_1_3()
+        generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
 };
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
index ab08cff..1bcf7bc 100644
--- a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
@@ -16,6 +16,7 @@
 
 package android.hardware.wifi.supplicant@1.3;
 
+import @1.0::ISupplicantStaNetwork;
 import @1.0::SupplicantStatus;
 import @1.2::ISupplicantStaNetwork;
 
@@ -24,6 +25,32 @@
  * configuration it controls.
  */
 interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork {
+    /** Possble mask of values for Proto param. */
+    enum ProtoMask : @1.0::ISupplicantStaNetwork.ProtoMask {
+        WAPI = 1 << 2,
+    };
+
+    /** Possble mask of values for KeyMgmt param. */
+    enum KeyMgmtMask : @1.2::ISupplicantStaNetwork.KeyMgmtMask {
+        /* WAPI Psk */
+        WAPI_PSK = 1 << 12,
+
+        /** WAPI Cert */
+        WAPI_CERT = 1 << 13,
+    };
+
+    /** Possble mask of values for PairwiseCipher param. */
+    enum PairwiseCipherMask : @1.2::ISupplicantStaNetwork.PairwiseCipherMask {
+        /** SMS4 Pairwise Cipher */
+        SMS4 = 1 << 7,
+    };
+
+    /** Possble mask of values for GroupCipher param. */
+    enum GroupCipherMask : @1.2::ISupplicantStaNetwork.GroupCipherMask {
+        /** SMS4 Group Cipher */
+        SMS4 = 1 << 7,
+    };
+
     /**
      * Set OCSP (Online Certificate Status Protocol) type for this network.
      *
@@ -49,6 +76,142 @@
     getOcsp() generates (SupplicantStatus status, OcspType ocspType);
 
     /**
+     * Set key management mask for the network.
+     *
+     * @param keyMgmtMask value to set.
+     *        Combination of |KeyMgmtMask| values.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setKeyMgmt_1_3(bitfield<KeyMgmtMask> keyMgmtMask) generates (SupplicantStatus status);
+
+    /**
+     * Get the key mgmt mask set for the network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return keyMgmtMask Combination of |KeyMgmtMask| values.
+     */
+    getKeyMgmt_1_3()
+        generates (SupplicantStatus status, bitfield<KeyMgmtMask> keyMgmtMask);
+
+    /**
+     * Set proto mask for the network.
+     *
+     * @param protoMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setProto_1_3(bitfield<ProtoMask> protoMask) generates (SupplicantStatus status);
+
+    /**
+     * Get the proto mask set for the network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return protoMask Combination of |ProtoMask| values.
+     */
+    getProto_1_3() generates (SupplicantStatus status, bitfield<ProtoMask> protoMask);
+
+    /**
+     * Set group cipher mask for the network.
+     *
+     * @param groupCipherMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setGroupCipher_1_3(bitfield<GroupCipherMask> groupCipherMask)
+        generates (SupplicantStatus status);
+
+    /**
+     * Get the pairwise cipher mask set for the network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return pairwiseCipherMask Combination of |PairwiseCipherMask| values.
+     */
+    getPairwiseCipher_1_3()
+        generates (SupplicantStatus status,
+            bitfield<PairwiseCipherMask> pairwiseCipherMask);
+
+    /**
+     * Set pairwise cipher mask for the network.
+     *
+     * @param pairwiseCipherMask value to set.
+     *        Combination of |ProtoMask| values.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setPairwiseCipher_1_3(bitfield<PairwiseCipherMask> pairwiseCipherMask)
+        generates (SupplicantStatus status);
+
+    /**
+     * Get the group cipher mask set for the network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return groupCipherMask Combination of |GroupCipherMask| values.
+     */
+    getGroupCipher_1_3()
+        generates (SupplicantStatus status,
+            bitfield<GroupCipherMask> groupCipherMask);
+
+    /**
+     * Set WAPI certificate suite for this network.
+     *
+     * @param suite value to set.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     */
+    setWapiCertSuite(string suite) generates (SupplicantStatus status);
+
+    /**
+     * Get WAPI certificate suite set for this network.
+     *
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |SupplicantStatusCode.SUCCESS|,
+     *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|,
+     *         |SupplicantStatusCode.FAILURE_UNKNOWN|
+     * @return suite The name of a suite.
+     */
+    getWapiCertSuite() generates (SupplicantStatus status, string suite);
+
+    /**
      * Add a PMK into supplicant PMK cache.
      *
      * @param serializedEntry is serialized PMK cache entry, the content is
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 2cf5881..ca3265e 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -227,3 +227,22 @@
             EXPECT_EQ(expectedStatusCode, status.code);
         });
 }
+
+/*
+ * GetKeyMgmtCapabilities_1_3
+ */
+TEST_F(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities_1_3) {
+    sta_iface_->getKeyMgmtCapabilities_1_3([&](const SupplicantStatus& status,
+                                               uint32_t keyMgmtMask) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        } else {
+            // Even though capabilities vary, these two are always set in HAL
+            // v1.3
+            EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::NONE);
+            EXPECT_TRUE(keyMgmtMask &
+                        ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X);
+        }
+    });
+}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
index 07bc9d8..d6f55f5 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -17,15 +17,18 @@
 #include <android-base/logging.h>
 
 #include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaIface.h>
 #include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
 
 #include "supplicant_hidl_test_utils.h"
 #include "supplicant_hidl_test_utils_1_3.h"
 
 using ::android::sp;
+using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaIface;
 using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
 using ::android::hardware::wifi::supplicant::V1_3::OcspType;
 namespace {
@@ -39,15 +42,37 @@
     virtual void SetUp() override {
         startSupplicantAndWaitForHidlService();
         EXPECT_TRUE(turnOnExcessiveLogging());
+        sta_iface_ = getSupplicantStaIface_1_3();
+        ASSERT_NE(nullptr, sta_iface_.get());
         sta_network_ = createSupplicantStaNetwork_1_3();
-        ASSERT_NE(sta_network_.get(), nullptr);
+        ASSERT_NE(nullptr, sta_network_.get());
     }
 
     virtual void TearDown() override { stopSupplicant(); }
 
    protected:
+    sp<ISupplicantStaIface> sta_iface_;
     // ISupplicantStaNetwork object used for all tests in this fixture.
     sp<ISupplicantStaNetwork> sta_network_;
+
+    bool isWapiSupported() {
+        uint32_t keyMgmtMask = 0;
+
+        // We need to first get the key management capabilities from the device.
+        // If WAPI is not supported, we just pass the test.
+        sta_iface_->getKeyMgmtCapabilities_1_3(
+            [&](const SupplicantStatus &status, uint32_t keyMgmtMaskInternal) {
+                EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+                keyMgmtMask = keyMgmtMaskInternal;
+            });
+
+        if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK)) {
+            // WAPI not supported
+            return false;
+        }
+
+        return true;
+    }
 };
 
 /*
@@ -84,3 +109,160 @@
             EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
         });
 }
+
+/*
+ * SetGetKeyMgmt_1_3, check new WAPI proto support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetKeyMgmt_1_3) {
+    uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_PSK;
+
+    sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        }
+    });
+
+    sta_network_->getKeyMgmt_1_3(
+        [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            } else {
+                EXPECT_EQ(keyMgmtOut, keyMgmt);
+            }
+        });
+
+    keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::WAPI_CERT;
+    sta_network_->setKeyMgmt_1_3(keyMgmt, [](const SupplicantStatus &status) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        }
+    });
+
+    sta_network_->getKeyMgmt_1_3(
+        [&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            } else {
+                EXPECT_EQ(keyMgmtOut, keyMgmt);
+            }
+        });
+}
+
+/*
+ * SetGetProto_1_3, check new WAPI proto support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetProto_1_3) {
+    uint32_t wapiProto = (uint32_t)ISupplicantStaNetwork::ProtoMask::WAPI;
+    sta_network_->setProto(wapiProto, [](const SupplicantStatus &status) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        }
+    });
+    sta_network_->getProto([&](const SupplicantStatus &status, uint32_t proto) {
+        if (SupplicantStatusCode::SUCCESS != status.code) {
+            // for unsupport case
+            EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+        } else {
+            EXPECT_EQ(proto, wapiProto);
+        }
+    });
+}
+
+/*
+ * SetGetGroupCipher_1_3, check new WAPI support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetGroupCipher_1_3) {
+    uint32_t groupCipher =
+        (uint32_t)ISupplicantStaNetwork::GroupCipherMask::SMS4;
+
+    sta_network_->setGroupCipher_1_3(
+        groupCipher, [](const SupplicantStatus &status) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            }
+        });
+
+    sta_network_->getGroupCipher_1_3(
+        [&groupCipher](const SupplicantStatus &status,
+                       uint32_t groupCipherOut) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            } else {
+                EXPECT_EQ(groupCipherOut, groupCipher);
+            }
+        });
+}
+
+/*
+ * SetGetPairwiseCipher_1_3, check new WAPI support
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetPairwiseCipher_1_3) {
+    uint32_t pairwiseCipher =
+        (uint32_t)ISupplicantStaNetwork::PairwiseCipherMask::SMS4;
+
+    sta_network_->setPairwiseCipher_1_3(
+        pairwiseCipher, [](const SupplicantStatus &status) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            }
+        });
+
+    sta_network_->getPairwiseCipher_1_3(
+        [&pairwiseCipher](const SupplicantStatus &status,
+                          uint32_t pairwiseCipherOut) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            } else {
+                EXPECT_EQ(pairwiseCipherOut, pairwiseCipher);
+            }
+        });
+}
+
+/*
+ * SetGetWapiCertSuite
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetWapiCertSuite) {
+    hidl_string testWapiCertSuite = "suite";
+
+    if (isWapiSupported()) {
+        sta_network_->setWapiCertSuite(
+            testWapiCertSuite, [](const SupplicantStatus &status) {
+                if (SupplicantStatusCode::SUCCESS != status.code) {
+                    // for unsupport case
+                    EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN,
+                              status.code);
+                }
+            });
+
+        sta_network_->getWapiCertSuite([testWapiCertSuite](
+                                           const SupplicantStatus &status,
+                                           const hidl_string &wapiCertSuite) {
+            if (SupplicantStatusCode::SUCCESS != status.code) {
+                // for unsupport case
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            } else {
+                EXPECT_EQ(testWapiCertSuite, wapiCertSuite);
+            }
+        });
+    } else {
+        sta_network_->setWapiCertSuite(
+            testWapiCertSuite, [](const SupplicantStatus &status) {
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            });
+
+        sta_network_->getWapiCertSuite(
+            [testWapiCertSuite](const SupplicantStatus &status,
+                                const hidl_string &wapiCertSuite __unused) {
+                EXPECT_EQ(SupplicantStatusCode::FAILURE_UNKNOWN, status.code);
+            });
+    }
+}